事件
React利用事件委托机制在document上统一监听DOM事件,再根据触发的target将事件分发到具体的组件实例。另外上面e是一个合成事件对象(SyntheticEvent),而不是原始的DOM事件对象。
React自定义一套事件系统的动机有以下几个:
- 抹平浏览器之间的兼容性差异
- 事件‘合成’, 即事件自定义
- 抽象跨平台事件机制
例子
1 | <html> |
组件在创建的时候会调用实例的 render方法,通过 createElement 创建 ReactComponent ,得到组件上的属性
在 workLoop 方法创建完整的 Fiber 树的链接关系。后在 completeWork 方法里的 createInstance方法 生成 stateNode后,添加绑定事件
1 | function setInitialDOMProperties(tag, domElement, rootContainerElement, nextProps, isCustomComponentTag) { |
触发点击事件
1 | function dispatchInteractiveEvent(topLevelType, nativeEvent) { |
补充
1. 在props初始化和更新时会进行事件绑定。首先React会判断元素是否是媒体类型
,媒体类型的事件是无法在Document监听的,所以会直接在元素上进行绑定
2. 反之就在Document上绑定. 这里面需要两个信息 第一个是事件依赖列表, 比如onMouseEnter
依赖mouseover/mouseout
; 第二个是ReactBrowserEventEmitter维护的’已订阅事件表’。事件处理器只需在Document订阅一次,所以相比在每个元素上订阅事件会节省很多资源.
1 | export function listenTo( |
遍历组件树来获取订阅该事件的用户事件处理器
1 | export function traverseTwoPhase(inst, fn, arg) { |
最终计算出来的_dispatchListeners
队列是这样的:[handleB, handleC, handleA]
参考资料
https://juejin.im/post/5d44e3745188255d5861d654
injectEventPluginsByName
1 | injectEventPluginsByName({ |
1 | function injectEventPluginsByName(injectedNamesToPlugins) { |
五种 eventPlugin
1 | BeforeInputEventPlugin |