React 事件原理

86 阅读3分钟

React事件都是‘假’的

  • 1 给元素绑定的事件,不是真正的事件处理函数。
  • 2 在冒泡/捕获阶段绑定的事件,也不是在冒泡/捕获阶段执行的。
  • 3 甚至在事件处理函数中拿到的事件源 e ,也不是真正的事件源 e 。

React 为什么要写出一套自己的事件系统呢?

兼容全浏览器

v17 之前 React 事件都是绑定在 document 上,v17 之后 React 把事件绑定在应用对应的容器 container 上,

独特的事件处理方式

  • 冒泡和捕获方法用Capture来区别
  • 阻止冒泡用e.stopPropagation()
  • 阻止默认行为e.preventDefault(),不能return false,因为不是真的事件处理函数

React 事件系统

React 事件系统可分为三个部分:

  • 第一个部分是事件合成系统(元素绑定的事件并不是原生事件,而是React 合成的事件,比如 onClick 是由 click 合成,onChange 是由 blur ,change ,focus 等多个事件合成。并且React 的事件不是绑定在元素上的,而是统一绑定在顶部容器上,在 v17 之前是绑定在 document 上的,在 v17 改成了 app 容器上。这样更利于一个 html 下存在多个应用(微前端)。)。

  • 第二个就是在一次渲染过程中,对事件标签中事件的收集,向 container 注册事件。比如onChange 和 onClick 会保存在对应 DOM 元素类型 fiber 对象( hostComponent )的 memoizedProps 属性上,然后遍历fiber的return对象,注册不同的事件插件(主要涉及到registrationNameModules插件负责映射合成事件的处理方法,registrationNameDependencies映射真正需要绑定哪些原生事件到container组件)

那么有一个疑问,绑定在 document 的事件处理函数是如上写的handleChange,handleClick 吗?

答案是否定的,绑定在 document 的事件,是 React 统一的事件处理函数 dispatchEvent ,React 需要一个统一流程去代理事件逻辑,包括 React 批量更新等逻辑。

  • 第三个就是一次用户交互,事件触发,到事件执行一系列过程。

事件触发

一次事件触发,比如点击,

  1. 首先打开批量更新开关,这个和更新state的时候一样
  2. 然后合成事件源,onClick 找到对应的处理插件 SimpleEventPlugin ,合成新的事件源 e ,里面包含了 preventDefault 和 stopPropagation 等方法。
  3. 形成事件执行队列,通过原生 DOM 获取到对应的 fiber ,接着会从这个 fiber 向上return遍历收集事件,用一个数组收集事件:
  • 如果遇到捕获阶段事件 onClickCapture ,就会 unshift 放在数组前面。以此模拟事件捕获阶段。
  • 如果遇到冒泡阶段事件 onClick ,就会 push 到数组后面,模拟事件冒泡阶段。
  • 一直收集到最顶端 app ,形成执行队列,在接下来阶段,依次执行队列里面的函数