- Published on
深入React - part 3
- Authors
- Name
- Deng Hua
目录
次章节着重描述react如何处理事件,以及背后React做了哪些工作
Event
DOM Event(前置知识提要)
DOM树中,事件如何传播。
假设现在在任一button
按钮上触发了一个click
事件,事件触发后会立即创建一个新的事件对象,但这个事件不是创建在button
按钮上,而是在document
根元素下创建,也就是在树的最顶端。
紧接着,事件将在捕获阶段中沿着整个树向下传播,直到到达target element
,在这里就是button
。在目标元素上我们可以在元素上放置事件处理函数来处理事件。
事件到达目标元素后,开始沿着树退回到根元素,即所谓的冒泡阶段。
在这个过程中,有两个重点:
- 在捕获和冒泡阶段,事件一一遍历了它的每个子元素和父元素,就像每个元素都经历了一次
"click"
一样。 - 默认情况下,事件处理函数不仅监听目标元素上的事件,也会监听到冒泡阶段中事件传播时经过的元素(经典的反向用法 -
e.stopPropagation
)。
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 PHASE
的Fiber Tree
的根节点上执行此操作。
如果代码中有多个点击类型的事件处理程序,React会将它们以某种方式绑定在一起,只需将一个大的点击事件处理程序添加到Fiber Tree
的根节点即可。
相当于react为我们应用中的所有事件执行了事件委托,也可以说react将所有事件委托给root
DOM元素,那里才是事件处理程序真正执行的地方,而不是我们认为注册的地方。
每当点击button
时,一个新的事件对象触发,然后它沿着DOM树向下移动,直到到达目标元素,然后事件开始冒泡返回,一旦事件到达react注册的根元素,该事件将根据对应的事件处理程序来执行。 最后事件会继续冒泡到document
元素,直至冒泡流程结束。
合成事件(SyntheticEvent)
每当我们声明一个事件处理函数时,react可以让我们访问创建的事件对象。
<input onChange={(e) => setText(e.target.value)} />
然而,这个事件对象和原生DOM事件不一样。
react给我们的,实际是一个**"合成事件"**,官方称为SyntheticEvent
。它基本是DOM的原生事件对象的封装。 因为这些合成事件与原生事件对象具有相同的接口,包括一些重要的方法(e.stopPropagation, e.preventDefault)等。 react也修复了一些因为浏览器不同导致API不同的问题,使得事件在所有浏览器都已完全相同的方式工作。
react团队认为所有最重要的合成事件实际上都是冒泡的,包括focus
,blur
,change
等。