React 事件处理
React 有一套自己独特的时间系统,实现统一管理,为实现跨浏览器、跨端的兼容处理。
组织冒泡
React 中如果想要阻止事件向上冒泡,可以用 e.stopPropagation() 。
阻止默认行为
React 中用 e.preventDefault() 阻止事件默认行为。
事件系统
React 事件系统可分为三个部分:
- 第一个部分是
事件合成系统,初始化会注册不同的事件插件。 - 第二个就是在一次渲染过程中,对事件标签中事件的收集,向 container
注册事件。 - 第三个就是一次用户交互,
事件触发,到事件执行一系列过程。
事件合成
- React 的事件不是绑定在元素上的,而是统一绑定在顶部容器上,在 v17 之前是绑定在 document 上的,在 v17 改成了 app 容器上。这样更利于一个 html 下存在多个应用(微前端)。
- onClick 就会用 SimpleEventPlugin 插件处理,onChange 就会用 ChangeEventPlugin 处理
- 此外React事件还会对应原生事件,绑定到 document 上的实际是原生事件。
- 一个react可能对应一个或者多个原生事件。
{
onBlur: ['blur'],
onClick: ['click'],
onClickCapture: ['click'],
onChange: ['blur', 'change', 'click', 'focus', 'input', 'keydown', 'keyup', 'selectionchange'],
onMouseEnter: ['mouseout', 'mouseover'],
onMouseLeave: ['mouseout', 'mouseover'],
...
}
事件绑定
对于标签上的事件 onChange 和 onClick 会保存在对应 DOM 元素类型 fiber 对象( hostComponent )的 memoizedProps 属性上,会绑定事件监听器。
绑定在 document 的事件不是我们实际写的handleClick函数,而是 React 统一的事件处理函数 dispatchEvent ,React 需要一个统一流程去代理事件逻辑,包括 React 批量更新等逻辑。
事件触发
一次点击事件的执行
- 批量更新
- 合成事件源
- 形成事件执行队列
在第一步通过原生 DOM 获取到对应的 fiber ,接着会从这个 fiber 向上遍历,遇到元素类型 fiber ,就会收集事件,用一个数组收集事件:
- 如果遇到捕获阶段事件 onClickCapture ,就会 unshift 放在数组前面。以此模拟事件捕获阶段。
- 如果遇到冒泡阶段事件 onClick ,就会 push 到数组后面,模拟事件冒泡阶段。
- 一直收集到最顶端 app ,形成执行队列,在接下来阶段,依次执行队列里面的函数。