React笔记-事件注册
事件机制
本系列以React v16.8.3为基础进行源码分析
React事件主要分为两部分: 事件注册与事件分发。下面先从事件注册说起。
事件注册
假设我们的程序如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
import React from 'react';
import ReactDOM from 'react-dom';
class ClickCounter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
handleClick = () => {
this.setState((state) => {
return {count: state.count + 1};
});
};
render() {
return [
<button key="1" onClick={this.handleClick}>Update counter</button>,
<span key="2">{this.state.count}</span>,
]
}
}
ReactDOM.hydrate(<ClickCounter />, document.getElementById('root'));
事件注册主要发生在初始化Dom属性的时候,调用setInitialProperties方法,对一些类型dom进行事件绑定。
switch (tag) {
case 'iframe':
case 'object':
trapBubbledEvent(TOP_LOAD, domElement);
props = rawProps;
break;
case 'video':
case 'audio':
for (var i = 0; i < mediaEventTypes.length; i++) {
trapBubbledEvent(mediaEventTypes[i], domElement);
}
props = rawProps;
break;
...
}
setInitialDOMProperties(tag, domElement, rootContainerElement, props, isCustomComponentTag);
...
接着调用setInitialDOMProperties来真正初始化Dom属性。根据当前workInProgress的pendingProps对象,给Dom对象设置属性。其中,有个分支会专门处理事件。
// registrationNameModules是一个map对象,存储着React支持的事件类型
else if (registrationNameModules.hasOwnProperty(propKey)) {
if (nextProp != null) {
ensureListeningTo(rootContainerElement, propKey);
}
}
执行ensureListeningTo方法:
// rootContainerElement为React应用的挂载点, registrationName为onClick
function ensureListeningTo(rootContainerElement, registrationName) {
// 判断rootContainerElement是document还是fragment
var isDocumentOrFragment = rootContainerElement.nodeType === DOCUMENT_NODE || rootContainerElement.nodeType === DOCUMENT_FRAGMENT_NODE;
// 获取rootContainerElement所在的document。
var doc = isDocumentOrFragment ? rootContainerElement : rootContainerElement.ownerDocument;
listenTo(registrationName, doc);
}
开始执行listenTo方法,注册事件入口。
// 获取当前已监听的原生事件类型的map
var isListening = getListeningForDocument(mountAt);
// 获取对应的原生事件类型,registrationNameDependencies存储了React事件类型与浏览器原生事件类型映射的一个map
var dependencies = registrationNameDependencies[registrationName];
for (var i = 0; i < dependencies.length; i++) {
var dependency = dependencies[i];
if (!(isListening.hasOwnProperty(dependency) && isListening[dependency])) {
switch (dependency) {
...// 除了scroll blur focus cancel close方法调trapCapturedEvent方法,invalid submit reset不处理之外,其余都调trapBubbledEvent方法。
default:
var isMediaEvent = mediaEventTypes.indexOf(dependency) !== -1;
if (!isMediaEvent) {
trapBubbledEvent(dependency, mountAt);
}
break;
}
// 标记该原生事件类型已被注册,下次注册同类型事件时会被忽略
isListening[dependency] = true;
}
}
trapCapturedEvent与trapBubbledEvent的区别是前者注册捕获阶段的事件监听器,后者注册冒泡阶段的事件监听器。trapCapturedEvent使用比较少,所以重点看下trapBubbledEvent。
//click document
function trapBubbledEvent(topLevelType, element) {
if (!element) {
return null;
}
// 从字面意能看出,前者是交互类事件,优先级会比普通事件高(click的分发者是dispatchInteractiveEvent)
var dispatch = isInteractiveTopLevelEventType(topLevelType) ? dispatchInteractiveEvent : dispatchEvent;
// 注册事件,在冒泡阶段捕获
addEventBubbleListener(element, getRawEventName(topLevelType),
// Check if interactive and wrap in interactiveUpdates
dispatch.bind(null, topLevelType));
}
总结
可以发现,React把某一类型事件通过事件代理绑定到document或fragment上(fragment的情况比较少)。即workInProgress在complete过程中,如果之前已经注册过onClick事件,后续workInProgress中的onClick事件将不再注册,统一由document中注册的click事件代理处理。
更好的阅读体验在我的github,欢迎
React笔记-事件注册的更多相关文章
- React笔记-事件分发
事件分发 之前讲述了事件如何绑定在document上,那么具体事件触发的时候是如何分发到具体的监听者呢?我们接着上次注册的事件代理看.当我点击update counter按钮时,触发注册的click事 ...
- 深入理解React:事件机制原理
目录 序言 DOM事件流 事件捕获阶段.处于目标阶段.事件冒泡阶段 addEventListener 方法 React 事件概述 事件注册 document 上注册 回调函数存储 事件分发 小结 参考 ...
- [技术博客]react native事件监听、与原生通信——实现对通知消息的响应
在react native中会涉及到很多页面之间的参数传递问题.静态的参数传递通常利用组件的Props属性,在初始化组件时即可从父组件中将参数传递到子组件中.对于非父子关系的组件来说,无法直接传递参数 ...
- libevent (三) 事件注册与循环监听
事件注册与循环监听 在libevent中为了监听某种事件的发生,设置事件触发后的回调函数,也就是说对该事件注册到当前的IO模型中. 事件注册 事件初始化 使用`event_new`函数来对事件进行初始 ...
- React笔记_(3)_react语法2
React笔记_(3)_react语法2 state和refs props就是在render渲染时,向组件内传递的变量,这个传递是单向的,只能继承下来读取. 如何进行双向传递呢? state (状态机 ...
- Flex timer使用 keydown事件注册到stage
Flex timer使用 keydown事件注册到stage: <?xml version="1.0" encoding="utf-8"?> < ...
- flex 事件注册和鼠标拖动
flex 事件注册和鼠标拖动 <?xml version="1.0" encoding="utf-8"?> <s:Application xm ...
- [JavaScript] JavaScript事件注册,事件委托,冒泡,捕获,事件流
面试题 event 事件 事件委托是什么? 如何阻止事件冒泡,阻止默认事件呢? Javascript 的事件流模型都有什么? 事件绑定和普通事件有什么区别? Event 对象 Event 对象,当事件 ...
- react 阻止事件冒泡
前言 在学习react阻止事件冒泡,需要先了解 合成事件 和 原生事件 合成事件:在jsx中直接绑定的事件,就是合成事件: 原生事件: 通过js原生代码绑定的事件,就是原生事件: react事件:re ...
随机推荐
- How to add hyperlink in JLabel
You can do this using a JLabel, but an alternative would be to style a JButton. That way, you don't ...
- Don't Dismiss Georgia Tech's $6,600 Online Master's Degree
https://www.pcmag.com/commentary/343924/dont-dismiss-georgia-techs-6-600-online-masters-degree Don't ...
- 用apiDoc简化接口开发
身为程序员最讨厌看到的代码没有注释,自己的代码却讨厌写注释,觉得麻烦,接口也是这样. 比如公司要做一个H5活动的页面,开发文档已经发到后端开发.设计.与前端的邮箱了,其实这个时候就可以开始开发了.开发 ...
- MyBatis 中的级联
MyBatis 的级联分为 3 种. 1.鉴别器(discriminator):它是根据某些条件决定采用具体实现类级联的方案,比如体检表要根据性别去区分. 2.一对一(association):比如学 ...
- Symbol Table Applications
符号表应用 在计算机发展的早期,符号表帮助程序员从使用机器语言的数字地址进化到在汇编语言中使用符号名称:在现代应用程序中,符号名称的含义能够通行于跨域全球的计算机网络.快速查找算法曾经并继续在计算机领 ...
- 阿里八八Alpha阶段Scrum(4/12)
今日进度 叶文滔: 整合了一下已完成的界面设计,修复了一些BUG. 问题困难:制作多级悬浮按钮阻碍重重,首先是刚更新不久的Andriod Studio 3.0向前兼容性差,一些语句规则的修改无所适从, ...
- windows下的MySql实现读写分离
MySql读写分离 1.删除系统服务 sc delete 服务名 2.复制安装好的3380文件夹到3381 3.进入3381\logs目录下将所有文件删除 4.进入3381\data目录,将所有的lo ...
- 矩阵dp
矩阵dp 这里是矩阵dp,不是矩阵乘法优化dp. 矩阵上的dp好像也没什么特殊的?大概有一个套路就是从上向下,从左向右进行dp吧. 首先第一道题好像不是矩阵dp... 1005 矩阵取数游戏:http ...
- 3130: [Sdoi2013]费用流
Description Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识. 最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案 ...
- Arduino入门笔记(2):Arduino的开发和virtualbreadboard仿真环境
欢迎加入讨论群 64770604 1.开发环境 (1)下载开发环境 Arduino的开发环境从http://arduino.cc/en/Main/Software官网下载即可,分为windows版本. ...