Published on

深入React - part 3

Authors
  • avatar
    Name
    Deng Hua
    Twitter

目录

次章节着重描述react如何处理事件,以及背后React做了哪些工作

Event

DOM Event(前置知识提要)

DOM树中,事件如何传播。

假设现在在任一button按钮上触发了一个click事件,事件触发后会立即创建一个新的事件对象,但这个事件不是创建在button按钮上,而是在document根元素下创建,也就是在树的最顶端。

紧接着,事件将在捕获阶段中沿着整个树向下传播,直到到达target element,在这里就是button。在目标元素上我们可以在元素上放置事件处理函数来处理事件。

事件到达目标元素后,开始沿着树退回到根元素,即所谓的冒泡阶段

在这个过程中,有两个重点:

  1. 在捕获和冒泡阶段,事件一一遍历了它的每个子元素和父元素,就像每个元素都经历了一次"click"一样。
  2. 默认情况下,事件处理函数不仅监听目标元素上的事件,也会监听到冒泡阶段中事件传播时经过的元素(经典的反向用法 - e.stopPropagation)。

dom event

React中的Event

一般的,这是在React中绑定一个点击事件的基本用法:

<button
  className='btn'
  onClick={() => setValue(false)}
>
</button>

只需要使用onClick属性来监听,然后传递一个函数给它,非常简单。那么React如何在背后实现注册这些事件处理程序呢?

我们第一时间想到的是,会不会也是通过这样的方法?

document.querySelector('.btn')
  .addEventListener(
    'click',
    () => {setValue(false)}
  )

实际上并不是。

React实际上是在应用的根元素上注册所有的事件处理函数。如果你使用CRA命令创建一个React应用,会看到应用通常是由一个<div id='root'>的元素渲染的,这个是应用根元素。

react选择根元素,然后将所有事件处理程序添加上去,它在RENDER PHASEFiber Tree的根节点上执行此操作。

如果代码中有多个点击类型的事件处理程序,React会将它们以某种方式绑定在一起,只需将一个大的点击事件处理程序添加到Fiber Tree的根节点即可。

相当于react为我们应用中的所有事件执行了事件委托,也可以说react将所有事件委托给rootDOM元素,那里才是事件处理程序真正执行的地方,而不是我们认为注册的地方。


每当点击button时,一个新的事件对象触发,然后它沿着DOM树向下移动,直到到达目标元素,然后事件开始冒泡返回,一旦事件到达react注册的根元素,该事件将根据对应的事件处理程序来执行。 最后事件会继续冒泡到document元素,直至冒泡流程结束。

dom event

合成事件(SyntheticEvent)

每当我们声明一个事件处理函数时,react可以让我们访问创建的事件对象。

<input onChange={(e) => setText(e.target.value)} />

然而,这个事件对象和原生DOM事件不一样。

react给我们的,实际是一个**"合成事件"**,官方称为SyntheticEvent。它基本是DOM的原生事件对象的封装。 因为这些合成事件与原生事件对象具有相同的接口,包括一些重要的方法(e.stopPropagation, e.preventDefault)等。 react也修复了一些因为浏览器不同导致API不同的问题,使得事件在所有浏览器都已完全相同的方式工作。

react团队认为所有最重要的合成事件实际上都是冒泡的,包括focus,blur,change等。

dom event