React 事件机制
react 并不会在该DOM元素上直接绑定事件处理器,而是实现了一套自己的事件机制,包括事件注册、事件的合成、事件执行。
自定义事件机制的动机:
- 抹平浏览器间的兼容性差异
- 改造原生事件,添加自定义属性
- 抽象事件机制实现跨平台开发
- 干预事件的分发以做到更好的优化
事件注册
事件注册做了两件事:事件注册、事件存储,完整的过程如下:
拿到需要被挂载的组件,调用 createElement 得到虚拟 DOM 树;
在虚拟 DOM 进行挂载、更新时,对组件的 props 进行处理,获取事件类型和回调函数;
挂载完成后,判断是否含有事件,如果有则在 document 上完成事件注册,并存储回调函数至 listenerBank 中;
V17 的改动
react v17 将不再往 document 上挂事件委托,而是挂载到 root DOM 上,主要是为了:
脱离 document 更方便于跨平台开发
解决多个 React 版本共存出现问题
合成事件的阻止冒泡现在会影响到手动添加的 DOM 事件的触发,因为 root DOM 会比 document 先一步接收到事件的冒泡:
document.addEventListener('click', function() { // This custom handler will no longer receive clicks // from React components that called e.stopPropagation() });
事件合成
合成事件包括:对原生事件的封装、对原生事件的改造、对不同浏览器的兼容。
封装原生事件
合成事件的回调函数会接收到 SyntheticEvent 的实例,实例拥有和浏览器原生事件一样的接口,原生的浏览器事件可以通过 nativeEvent 属性来获得
改造原生事件
react并不是只处理你声明的事件类型,还会额外的增加一些其他的事件,帮助我们提升交互的体验。
例如在绑定 onChange 事件后,react 会在 SyntheticEvent 实例中额外注册 invalid 事件。
兼容浏览器
例如 react 在绑定事件方面对 ie8 及早期版本进行兼容,使用 target.attachEvent()
替换target.addEventListener()
事件执行
事件执行的主要步骤:
- 事件冒泡到 document;
- 执行统一的事件分发函数 dispatchEvent;
- 找到当前事件对应的 ReactDOMComponent 对象;
- 进行事件的合成;
- 批量处理合成事件内的回调事件;