React15 - React15应用中的事件订阅和发送机制
在React 15中,我们平时使用的onClick、onChange这样写好的事件,其实幕后有一套“订阅/发送”的机制在运作。这套机制和我们通常理解的手动监听和触发自定义事件不同,它内嵌于React的底层,核心是事件委托和统一的事件调度。
React 15的事件系统就像一个智能的“事件中转站”,所有组件声明的事件处理函数(订阅者)并不直接绑定在真实的DOM节点上,而是统一“寄存”在React内部的一个全局对象中,并在document上监听所有事件。当浏览器事件发生时(发送),由document上唯一的监听器接收,然后根据事件类型和目标,去那个全局对象里找到对应的处理函数并执行。
这个过程主要分为两大步:订阅(事件注册与存储) 和 发送(事件触发与执行)。
📝 订阅:事件如何被“登记在册”
在组件挂载阶段,React会完成“订阅”操作,也就是把我们写的onClick等处理函数保存起来。
- 处理JSX属性:当React解析到JSX中的
onClick={this.handleClick}属性时,它会识别出这是一个事件声明。 - 在
document上注册:React会确保在document上已经为click这种事件类型注册了一个统一的监听函数,叫dispatchEvent。如果之前注册过,这一步就会跳过。 - 将回调函数存储到
listenerBank:最关键的一步是,React会把当前组件实例和它的handleClick函数关联起来,存储到一个叫做listenerBank的全局对象中。这个对象就像一个中央“电话本”,以事件类型(如onClick)和组件ID为索引,记录了所有需要被回调的函数。
📣 发送:事件如何被“精准派发”
当用户真的点击了按钮,事件的“发送”流程就开始了。
- 统一接收:浏览器原生事件冒泡到
document,被我们之前注册好的dispatchEvent函数统一接收。 - 创建“合成事件”:
dispatchEvent会根据原生事件,创建一个符合W3C规范的SyntheticEvent(合成事件)对象。这个对象包装了原生事件,抹平了不同浏览器的差异,你可以像使用原生事件一样使用它(例如e.preventDefault())。 - 查找事件路径:事件系统会从触发事件的节点开始,向上遍历所有父节点,构建出一个包含所有相关组件实例的“路径”数组。
- 从“电话本”中匹配回调:沿着这个路径,React会根据当前事件类型(如
onClick)和遍历到的组件实例ID,去listenerBank这个中央存储里查找对应的回调函数。找到后,就把这些回调函数依次放入合成事件对象的执行队列中。 - 批量执行回调:最后,React会批量执行队列中的回调函数,模拟出事件在DOM树中捕获和冒泡的过程。同时,它也提供了在合成事件对象上调用
stopPropagation()来阻止这个模拟冒泡的能力。
💡 理解这套机制的意义
理解这套内建的“订阅/发送”机制,能帮你更好地使用React:
- 避免混合使用原生和合成事件:如果在同一个DOM节点上同时绑定了原生事件和React的合成事件,原生事件会先执行。如果在原生事件中调用了
stopPropagation(),就会阻止事件冒泡到document,从而导致React的合成事件无法被触发。 - 提升性能:React的事件委托模式意味着无论你有多少个组件,每种事件类型只在
document上注册一次,这大大减少了内存消耗。 - 统一事件行为:你得到的
e参数是一个标准化的事件对象,无论在哪个浏览器上,它的属性和方法都是一致的,省去了处理兼容性的麻烦。

浙公网安备 33010602011771号