首页 > 其他分享 >17 | React 事件机制

17 | React 事件机制

时间:2022-12-30 18:13:36浏览次数:70  
标签:遍历 17 DOM React 事件 机制 document 节点

  无论是在面试场景下,还是在实际的开发中,React 事件相关的问题都更倾向于考验我们对事件工作流、事件特征等逻辑层面问题的理解,而非对源码细节的把握。所以掌握事件工作流、事件特征等逻辑层面的“主要矛盾”就可以。

回顾原生 DOM 下的事件流

W3C 标准约定了一个事件的传播过程要经过以下 3 个阶段:

  1. 事件捕获阶段

  2. 目标阶段

  3. 事件冒泡阶段

在原生 DOM 中,事件委托(也叫事件代理)是一种重要的性能优化手段。利用事件的冒泡特性,把多个子元素的同一类型的监听逻辑,合并到父元素上通过一个监听函数来管理的行为,就是事件委托。通过事件委托,我们可以减少内存开销、简化注册步骤,大大提高开发效率。这绝妙的事件委托,正是 React合成事件的灵感源泉。

React 事件系统是如何工作的

当事件在具体的 DOM 节点上被触发后,最终都会冒泡到 document 上,document 上所绑定的统一事件处理程序会将事件分发到具体的组件实例。在分发事件之前,React 首先会对事件进行包装,把原生 DOM 事件包装成合成事件。

认识 React 合成事件

合成事件是 React 自定义的事件对象,它符合W3C规范,在底层抹平了不同浏览器的差异,在上层面向开发者暴露统一的、稳定的、与 DOM 原生事件相同的事件接口。虽然合成事件并不是原生 DOM 事件,但它保存了原生 DOM 事件的引用。当你需要访问原生 DOM 事件对象时,可以通过合成事件对象的 e.nativeEvent 属性获取到它。

React 事件系统工作流拆解

事件的绑定是在组件的挂载过程中完成的,具体来说,是在 completeWork 中完成的。completeWork 内部有三个关键动作:创建 DOM 节点(createInstance)、将 DOM 节点插入到 DOM 树中(appendAllChildren)、为 DOM 节点设置属性(finalizeInitialChildren)。

其中“为 DOM 节点**设置属性”**这个环节,会遍历 FiberNode 的 props key。当遍历到事件相关的 props 时,就会触发事件的注册链路。工作流如下:

从图中可以看出,事件的注册过程是由 ensureListeningTo 函数开启的。在 ensureListeningTo 中,会尝试获取当前 DOM 结构中的根节点(这里指的是 document 对象),然后通过调用 legacyListenToEvent,将统一的事件监听函数注册到 document 上面。

最后绑定到 document 上的这个统一的事件分发函数,其实就是 dispatchEvent,针对同一个事件,即便可能会存在多个回调,document 也只需要注册一次监听,比如说我尝试监听的是一个点击事件,那么 topLevelType 的值就会是 click,如下若事件系统识别到 listenerMap.has(topLevelType) 为 true,也就是当前这个事件 document 已经监听过了,那么就会直接跳过对这个事件的处理,否则才会进入具体的事件监听逻辑。如此一来,即便我们在 React 项目中多次调用了对同一个事件的监听,也只会在 document 上触发一次注册。

那么 dispatchEvent 是如何实现事件分发的呢?

事件触发的本质是对 dispatchEvent 函数的调用,直接来看核心工作流,请看下图:

1-3步如上介绍
4.循环收集符合条件的父节点,存进 path 数组中。以当前节点(触发事件的目标节点)为起点,不断向上寻找 父节点,并将这些节点按顺序收集进 path 数组中
5.模拟事件在捕获阶段的传播顺序,收集捕获阶段相关的节点实例与回调函数。会从后往前遍历 path 数组,模拟事件的捕获顺序,收集事件在捕获阶段对应的回调与实例。从后往前遍历 path 数组,其实就是从父节点往下遍历子节点,直至遍历到目标节点的过程,这个遍历顺序和事件在捕获阶段的传播顺序是一致的
6.模拟事件在冒泡阶段的传播顺序,收集冒泡阶段相关的节点实例与回调函数。捕获阶段的工作完成后,traverseTwoPhase 会从前往后遍历 path 数组,模拟事件的冒泡顺序,收集事件在捕获阶段对应的回调与实例。

React 事件系统的设计动机是什么?

在底层抹平了不同浏览器的差异,在上层面向开发者暴露统一的、稳定的、与 DOM 原生事件相同的事件接口。开发者们由此便不必再关注烦琐的底层兼容问题,可以专注于业务逻辑的开发。

自研事件系统使 React 牢牢把握住了事件处理的主动权,通过自研事件系统,React 能够从很大程度上干预事件的表现,使其符合自身的需求。比如说它想在事件系统中处理 Fiber 相关的优先级概念,或者想把多个事件揉成一个事件(比如 onChange 事件)

React 合成事件虽然承袭了事件委托的思想,但它的实现过程比传统的事件委托复杂太多。至于 React 事件是否比不使用事件委托的原生 DOM 事件性能更好?没有严格的对比和大量测试数据做支撑,我们很难下结论。

标签:遍历,17,DOM,React,事件,机制,document,节点
From: https://www.cnblogs.com/superlizhao/p/17015523.html

相关文章

  • react-router 同一路由,参数不同,页面没有刷新
    react-router同一路由,参数不同,页面没有刷新2020-01-1117:53:04使用componentWillReceiveProps(newProps)函数,当props改变时,我们就可以在该函数中通过newProps.ma......
  • 【Storm篇】--Storm并发机制
    =========================================================声明:由于不同平台阅读格式不一致(尤其源码部分),所以获取更多阅读体验!!个人网站地址:​​http://www.lhworldblog.......
  • 【Storm篇】--Storm 容错机制
    =========================================================声明:由于不同平台阅读格式不一致(尤其源码部分),所以获取更多阅读体验!!个人网站地址:​​http://www.lhworldblog.......
  • Redux+React-Redux 最新入门实战指南?
    大家好,我是CoderBin前言本文将给大家带来redux和react-redux的快速使用,以理论+代码+案例的形式教大家如何在react中去使用状态管理,以实现数据的高效通信......
  • Java集合快速失败和安全失败机制
    快速失败机制是Java集合的一种错误检测机制,当遍历集合时,集合的结构进行了修改,可能会触发"fail-fast"机制Java.util包中所有集合都被设计为快速失败机制示例代码public......
  • vue3的shallowRef()和shallowReactive()
    1.shallowReactive():使用shallowReactive转化的对象只有对象的第一层级有响应式。   2.shallowRef():使用shallowRef转化的基本数据类型和使用ref没有差别,使用shallo......
  • WPF中使用委托机制更新UI内容
    在开发WPF应用程序时,UI线程不做高负载的工作,需要交给其他工作者线程去干。当工作者线程干完活得到一个结果后需要发送给UI线程进行展示,那最好的方法就是使用委托机制了。如......
  • 操作系统实战45讲00017
    你好,我是LMOS。今天我们继续来研究Linux的初始化流程,为你讲解如何解压内核,然后讲解Linux内核第一个C函数。最后,我们会用Linux的第一个用户进程的建立来收尾。如果用你上......
  • React
    1.概述2.安装配置操作系统:MACOS开发工具:VSCODE2.1安装工具node官网下载安装:https://nodejs.org/en/安完后,就可以使用npm命令了cnpmnpm命令下载的包,都是......
  • 存储机制(Window.sessionStorage 和 Window.locaStorage)
    <!DOCTYPEhtml><html> <head> <metacharset="utf-8"> <title>webStorage</title> <!-- 1.存储内容大小一般支持5MB左右(不同浏览器可能不一样) 2.浏览器通过Window.......