React Capture Event

React

React 为了消除不同浏览器上的 Event 差异,设计了一套合成事件(SyntheticEvent)。一般常用的有 onClickonKeyDown 等等。

类似于原生的浏览器事件,React 的合成事件也有捕获和冒泡两个不同的阶段。一般常用的 onClick 是在冒泡阶段的回调函数,对应的捕获阶段的回调函数是 onClickCapture

需要注意的是,React 合成事件的设计,是在顶层元素上捕获事件,然后通过 React 内部的机制生成对应的合成事件,并转发给 React 元素。其中的捕获和冒泡是由 React 自身来维护的。通过下面的例子,可以直观的看到 React 合成事件和原生浏览器的事件之间的执行顺序。

假设有下面一段 HTML 代码:

<div id="not-react-dom-outer">
  <div id ="not-react-dom-inner">
    <div id="app"></div>
  </div>
</div>

以及下面这段配套的 JavaScript 代码:

const outer = document.querySelector('#not-react-dom-outer');
outer.addEventListener('click', function(e) {
  console.log('not-react-dom-outer (bubble)');
}, false);
outer.addEventListener('click', function(e) {
  console.log('not-react-dom-outer (capture)');
}, true);
 
const inner = document.querySelector('#not-react-dom-inner');
inner.addEventListener('click', function(e) {
  console.log('not react div inner (bubble)');
}, false);
inner.addEventListener('click', function(e) {
  console.log('not react div inner (capture)');
}, true);

const Button = () => (
  <div
    onClick={() => console.log('react div (bubble)')}
    onClickCapture={() => console.log('react div (capture)')}
  >
    <button
      onClick={() => console.log('react button (bubble)')}
      onClickCapture={() => console.log('react button (capture)')}
    >
      Click Me
    </button>
  </div>
);

ReactDOM.render(<Button />, document.getElementById('app'));

那么,在点击了 <button> 按钮之后,控制台的输出顺序为:

not-react-dom-outer (capture)
not react div inner (capture)
not react div inner (bubble)
not-react-dom-outer (bubble)
react div (capture)
react button (capture)
react button (bubble)
react div (bubble)

执行顺序上是先完成了从捕获到冒泡的所有原生事件,然后再执行从捕获到冒泡的所有 React 合成事件。

关于合成事件,可以参考官方给出的文档