til
  • README
  • Software Development Roles
  • solid
  • README
    • service-worker
  • docker
    • arg
    • 更新docker版本
  • editor
    • vscode
    • Creating a VS Code Theme
  • english
    • words
  • front-end
    • ==
    • ECMAScript
    • IIFE
    • Label
    • basic
    • html.js.css渲染顺序
    • npm-vs-yarn
    • obj-delete-key-value
    • react
    • split-join-and-replace
    • video
    • 前端自检清单
    • 递归及去重
    • css
      • css换肤
      • flex
      • list
      • nth-child和nth-of-type区别
      • padding
      • position
      • 层叠上下文
      • 层叠样式(+)
      • 正方形
      • 语义化标签
    • dom
      • DOCTYPE
      • HEAD
      • 修改document
      • 自定义表单验证
    • electron
      • basic
    • es6
      • basic-type
      • basic
      • prototype-example
      • defineProperty
      • understanding-es6
        • 0.introduction
        • Appendix A: Smaller Changes
        • Appendix B: Understanding ES7
        • Block-Binding
        • Proxies&Reflection
        • class
        • 解构赋值
        • function
        • improved-array
        • iterators&generators
        • modules
        • object
        • promise
        • Map&Set
        • symbol
    • images
      • 前端角度看图片
    • interview_case
      • lexical_scope
      • redux和localstroage存储位置
    • javascript
      • fuck-the-js
      • js-engine-work
      • js原生操作dom
      • what-is-function-program
      • 执行上下文
      • articles
        • JavaScript中使用函数组合
        • JavaScript中的依赖注入
        • JavaScript作用域链中的标识符解析和闭包
        • JavaScript是何如工作的--概述
        • JavaScript深拷贝
        • JavaScript的全局变量是如何工作的
        • js继承常见的误解
        • node12&chrome中7个新的提案功能
        • 你真的懂JavaScript吗
      • date
        • index
      • engines
        • basic
        • JavaScript引擎基础:外形和内联缓存
        • v8中推测性优化的介绍
        • 优化原型
        • 更快的异步功能和promise
      • events
        • baisc
        • 事件冒泡和捕获
        • 定义事件
        • 页面生命周期
      • higher-order-function
        • curry
        • monad
      • module
        • basic
        • main&module
      • objects
        • iterator
        • spread
        • examples
          • iterator
      • performance
        • blocking-css
        • cache
      • prototype
        • Property-Descriptors
        • basic
        • prototype-shadow
      • you-dont-known-js
        • async&performance
          • Chapter 1: Asynchrony: Now & Later
          • Chapter 2: Callbacks
          • Chapter 3: Promises
          • Chapter 4: Generators
        • scope & closures
          • apA
          • apB
          • apC
          • apD
          • chapter1-what-is-scope
          • chapter2-lexical-scope
          • chapter3-function-vs-block-scope
          • chapter4-hoisting
          • chapter5-scope-closure
        • this & object prototypes
          • chapter1-this-or-that
          • chapter2-this-make-sense
          • chapter3-objects
          • chapter4-mixing(up)-class-object
          • chapter5-prototype
          • chapter6-behavior-delegation
        • types&grammer
          • Chapter1-Types
          • Chapter2-Values
          • Chapter3-Natives
          • Chapter4-coercion
          • Chapter5-grammer
        • up & going
          • chapter1-into-programming
          • chapter2-into-javascript
          • chapter3-into-YDKJS
    • mobile
      • iPhone分辨率终极指南
    • npm
      • arguments
      • build
    • react-native
      • prop-methods
    • react
      • PropTypes
      • basic
      • codebase-overview
      • component-element-instance
      • context
      • how-to-known-component-is-func-or-class
      • overview
      • react16.9
      • react18计划
      • react的设计原则
      • reconciliation
      • setState
      • useMemo
      • why-do-we-write-super-props
      • 从头实现一个react
      • concurrent
        • 引入并发模式(仅试验)
      • conf
        • conf-2019
      • events
        • 合成事件概述
      • hooks
        • custom-hook
        • effect-hook
        • hooks-api
        • intro
        • overview
        • rules
        • state-hook
        • hooks-vs-class
          • thinking-in-react-hooks
      • overreact
        • Development模式是如何工作的
        • How-Does-setState-Know-What-to-Do
        • Why-Do-React-Elements-Have-a-$$typeof-Property
        • Why-Do-React-Hooks-Rely-on-Call-Order
        • how-to-known-component-is-func-or-class
        • preparing-tach-talk-motivation
        • react作为ui运行
        • things-i-dont-known-as-2018
        • ui-element-problem-and-build-yourself
        • why-do-we-write-super-props
        • 一份完整的useEffect指南
        • 为什么X不是Hook
        • 函数组件与类有什么不同?
        • 演讲准备2-what-why-how
        • 编写弹性组件
        • 让setInterval在React-Hooks中为声明式
      • practice
        • render
      • react-dom
        • basic
      • react-redux
        • apiv7.1-hooks
        • connect
        • shallow-equal
      • redux
        • applyMiddleware
        • applyMiddleware2-细节
        • example
    • regex
      • index
    • stories
      • 数组下标
      • 阻止事件冒泡
    • svelte
      • compile-svelte-in-your-head-1
      • compiler-overview
      • parser
        • 写一个解析器-JavaScript的JSON解析器
    • turbopack
      • basic
    • typescript
      • interface和type的区别
    • webpack
      • hash
      • webpack4-for-react
      • webpack4
      • webpack4to5
      • babel
        • babel-parser和acorn的区别
        • babel.7.11
        • family
        • react16.14使用new-transform
        • update-to-7
    • pdf
      • deep-js
        • basic
      • react
        • reintroducing
  • git
    • capital
    • emoji
  • http
    • http2.0
    • response
  • rails
    • api
    • flash
    • middleware-vs-metal
    • model
    • performance
    • routes
    • environment
      • error
    • patterns
      • service
    • sidekiq
      • params
    • deploy
      • capistrano
        • ssh
  • ruby
    • self
    • net
      • http请求携带cookie
  • server
    • ss
    • ssh
    • user
    • crawler
      • puppeteer
    • nginx
      • domain-without-80
      • nginx节省带宽
  • sql
    • rails
    • search
Powered by GitBook
On this page
  1. front-end
  2. react
  3. events

合成事件概述

如果各位看了react的源码,会发现在事件处理的代码里,有那么一段注释:

/**
 * Summary of `ReactBrowserEventEmitter` event handling:
 *
 *  - Top-level delegation is used to trap most native browser events. This
 *    may only occur in the main thread and is the responsibility of
 *    ReactDOMEventListener, which is injected and can therefore support
 *    pluggable event sources. This is the only work that occurs in the main
 *    thread.
 *
 *  - We normalize and de-duplicate events to account for browser quirks. This
 *    may be done in the worker thread.
 *
 *  - Forward these native events (with the associated top-level type used to
 *    trap it) to `EventPluginHub`, which in turn will ask plugins if they want
 *    to extract any synthetic events.
 *
 *  - The `EventPluginHub` will then process each event by annotating them with
 *    "dispatches", a sequence of listeners and IDs that care about that event.
 *
 *  - The `EventPluginHub` then dispatches the events.
 *
 * Overview of React and the event system:
 *
 * +------------+    .
 * |    DOM     |    .
 * +------------+    .
 *       |           .
 *       v           .
 * +------------+    .
 * | ReactEvent |    .
 * |  Listener  |    .
 * +------------+    .                         +-----------+
 *       |           .               +--------+|SimpleEvent|
 *       |           .               |         |Plugin     |
 * +-----|------+    .               v         +-----------+
 * |     |      |    .    +--------------+                    +------------+
 * |     +-----------.--->|EventPluginHub|                    |    Event   |
 * |            |    .    |              |     +-----------+  | Propagators|
 * | ReactEvent |    .    |              |     |TapEvent   |  |------------|
 * |  Emitter   |    .    |              |<---+|Plugin     |  |other plugin|
 * |            |    .    |              |     +-----------+  |  utilities |
 * |     +-----------.--->|              |                    +------------+
 * |     |      |    .    +--------------+
 * +-----|------+    .                ^        +-----------+
 *       |           .                |        |Enter/Leave|
 *       +           .                +-------+|Plugin     |
 * +-------------+   .                         +-----------+
 * | application |   .
 * |-------------|   .
 * |             |   .
 * |             |   .
 * +-------------+   .
 *                   .
 *    React Core     .  General Purpose Event Plugin System
 */

来一步步的解析,让这货更明朗起来。

Top-level delegation is used to trap most native browser events. This may only occur in the main thread and is the responsibility of ReactDOMEventListener, which is injected and can therefore support pluggable event sources. This is the only work that occurs in the main thread.

React为每个事件类型使用一个事件侦听器来调用虚拟DOM中所有提交的处理程序。看看下面的这个例子:

const ExampleComponent = () => (
  <div onClick={onClick}>
    <div onClick={onClick} />
  </div>
)

这样我们就将在原生DOM上为click事件注册一个事件侦听器。我们在Chrome开发工具上运行getEventListeners(document.querySelector('button'))方法,我们将得到类似的以下结果:

{click: Array(n)} //n is number

每个事件类型的监听器都会在每个渲染周期中得到保证,所以如果我们定义额外的keydown类型的事件处理程序,我们会得到如下输出:

{click: Array(n), keydown: Array(1)}

We normalize and de-duplicate events to account for browser quirks. This may be done in the worker thread.

对于每个浏览器,无论其实现如何,都将拥有一致的事件参数,因为React将它们规范化。 由于 React 为多个处理程序注册了单个事件侦听器, 因此它需要为每个处理程序重新分配事件。

Forward these native events (with the associated top-level type used to trap it) to EventPluginHub, which in turn will ask plugins if they want to extract any synthetic events.

合成事件是React的规范化事件参数,它确保所有浏览器之间的一致性,并由插件生成。注意,合成事件正在被合并!这意味着相同的对象实例在多个处理程序中使用,只是在每次调用前都使用新属性重置它,然后处理:

function onClick(event) {
  console.log(event); // => nullified object.
  console.log(event.type); // => "click"
  const eventType = event.type; // => "click"
  setTimeout(function() {
    console.log(event.type); // => null
    console.log(eventType); // => "click"
  }, 0);
  // Won't work. this.state.clickEvent will only contain null values.
  this.setState({clickEvent: event});
  // You can still export event properties.
  this.setState({eventType: event.type});
}

The EventPluginHub will then process each event by annotating them with "dispatches", a sequence of listeners and IDs that care about that event.

前面也提到了,每个事件都可以有多个处理程序,即使每个处理程序实际上都被真正的 DOM 侦听一次。因此, 需要累积由事件处理程序及其相应的fiber节点(虚拟 DOM 树中的节点)组成的相关 "调度", 以便后面的使用。

The EventPluginHub then dispatches the events.

插件遍历之前累积的信息并调度事件,从而调用提交的事件处理程序。

本文就说了那么多,但是有几点希望你可以知道:

  • 注册到主DOM (window.document)的顶级事件监听器也可以注册到其他DOM,这取决于应用程序容器的位置。比如,容器被iframe采用,那么iframe的DOM将是主要的事件监听器; 它也可以是一个文档片段、一个shadow DOM 等。重要的是,你应该意识到这一点,并知道事件的传播有这小小的限制。

  • React将事件重新调度分为两个阶段: 一个用于捕获,另一个用于冒泡,就像原生DOM那样。

参考:

PreviouseventsNexthooks

Last updated 6 years ago

下面就来说说这个。如果图片更直接,那么就来看看这个图片: 可以发现,和上面注释里没啥区别。

EventPluginHub是React事件处理系统中的一个非常核心的组件。这就是将所有事件插件统一到一个位置的方法,并将被分派的事件重定向到每个事件。每个插件负责提取和处理不同的事件类型,例如,有SimpleEventPlugin来处理可能在大多数浏览器中实现的事件,比如鼠标事件和按键(); 还有ChangeEventPlugin,它就是处理大家都知道的onChange事件()。

为React Native完成的事件处理与React DOM不同,你不应该混淆这两者! React只是一个库,它生成我们想要呈现的视图的虚拟表示,React DOM/Native是React和我们使用的环境之间的桥梁。(对于这个,可以)。本文仅与React DOM相关!

源码
源码
参考这个地方
Getting to know React DOM’s event handling system inside out
The React and React Native Event System Explained: A Harmonious Coexistence
Mixing React and DOM events
react event