Appearance
React 事件处理机制:从事件提取到分发的完整流程
在 React 的事件系统中,从原生 DOM 事件触发到最终执行组件中的事件处理函数,需要经历两个关键阶段:事件提取(Event Extraction) 和 事件分发(Event Dispatch)。这两个阶段共同构成了 React 事件处理的核心机制,确保了跨浏览器的一致性和高效的事件管理。
事件提取机制
当一个原生 DOM 事件被触发并由 React 的根监听器捕获后,并不会立即将这个原生事件直接派发给组件。相反,它会进入一个"事件提取"阶段,这个阶段的核心职责是将原生 DOM 事件转换为 React 的合成事件 (SyntheticEvent
),并收集与该事件相关的监听器。
顶层 extractEvents
函数
在 react/packages/react-dom-bindings/src/events/DOMPluginEventSystem.js
文件中,有一个名为 extractEvents
函数,它的职责是按顺序调用注册在系统中的各个事件插件的 extractEvents
方法。
extractEvents 函数
javascript
// ... existing code ...
function extractEvents(
dispatchQueue: DispatchQueue, // 用于收集事件和监听器的队列
domEventName: DOMEventName, // 触发的原生 DOM 事件名 (如 'click')
targetInst: null | Fiber, // 与原生事件目标最近的 Fiber 实例
nativeEvent: AnyNativeEvent, // 原生浏览器事件对象
nativeEventTarget: null | EventTarget, // 原生事件的目标 DOM 元素
eventSystemFlags: EventSystemFlags, // 事件系统标志 (如是否捕获阶段)
targetContainer: EventTarget, // 事件发生的根容器
) {
// 1. 首先调用 SimpleEventPlugin 的 extractEvents
// SimpleEventPlugin 处理大部分简单事件的映射和分发逻辑
SimpleEventPlugin.extractEvents(
dispatchQueue,
domEventName,
targetInst,
nativeEvent,
nativeEventTarget,
eventSystemFlags,
targetContainer,
);
// 2. 根据 eventSystemFlags 判断是否需要处理其他"polyfill"性质的插件
const shouldProcessPolyfillPlugins =
(eventSystemFlags & SHOULD_NOT_PROCESS_POLYFILL_EVENT_PLUGINS) === 0;
// 通常情况下,这些插件只在原生事件的"冒泡"阶段被处理,
// 因为 React 仍然在内部模拟捕获阶段,直接在捕获阶段调用这些插件可能会导致状态问题。
if (shouldProcessPolyfillPlugins) {
// 3. 依次调用其他插件的 extractEvents 方法
EnterLeaveEventPlugin.extractEvents(...);
ChangeEventPlugin.extractEvents(...);
SelectEventPlugin.extractEvents(...);
BeforeInputEventPlugin.extractEvents(...);
FormActionEventPlugin.extractEvents(...); // 如果启用了相关特性
// ScrollEndEventPlugin.extractEvents(...); // 如果启用了相关特性
}
}
// ... existing code ...
事件插件内部的 extractEvents
方法
每个事件插件(如 SimpleEventPlugin
, ChangeEventPlugin
, EnterLeaveEventPlugin
等)都必须实现一个 extractEvents
方法。这个方法是插件的核心,它接收与顶层 extractEvents
函数类似的参数。
其主要职责包括(以 SimpleEventPlugin 为例):
- 映射原生事件到 React 事件名:将如
click
映射到onClick
- 选择合适的合成事件构造函数:根据原生事件类型(如
MouseEvent
,KeyboardEvent
)选择对应的SyntheticMouseEvent
,SyntheticKeyboardEvent
等 - 处理特定事件的浏览器兼容性问题:例如,过滤掉 Firefox 中由鼠标右键触发的 click 事件,或处理 focusin/focusout 到 onFocus/onBlur 的转换
- 收集监听器:调用
accumulateSinglePhaseListeners
(或在特定情况下调用accumulateEventHandleNonManagedNodeListeners
)来遍历 Fiber 树,收集捕获和冒泡阶段的事件处理函数 - 创建合成事件对象:如果收集到监听器,则创建一个合成事件实例
- 推入调度队列:将合成事件和监听器列表推入 dispatchQueue
📱 想了解更多 React 事件处理机制?
本文只是 React 事件处理机制深度解析的一部分内容。想要获取完整的技术文章和更多 React 源码解析内容,请关注我的微信公众号!
🔥 关注公众号获取:
- 完整的 React 事件分发流程解析
- React 合成事件的底层实现
- 事件插件系统的设计原理
- React 性能优化最佳实践
- 前端架构设计思路
- 最新技术趋势分析
📲 扫码关注
公众号:前端小卒
专注于前端技术的深度剖析,带你从源码层面理解 React、Vue 等主流框架的设计思想和实现原理。每周更新,干货满满!
本文为预览版本,完整内容请关注公众号获取。