React 事件机制原理

相关问题

  • React 合成事件与原生 DOM 事件的区别
  • React 如何注册和触发事件
  • React 事件如何解决浏览器兼容问题

回答关键点

React 的事件处理机制可以分为两个阶段:初始化渲染时在 root 节点上注册原生事件;原生事件触发时模拟捕获、目标和冒泡阶段派发合成事件。通过这种机制,冒泡的原生事件类型最多在 root 节点上注册一次,节省内存开销。且 React 为不同类型的事件定义了不同的处理优先级,从而让用户代码及时响应高优先级的用户交互,提升用户体验。

React 的事件机制中依赖合成事件这个核心概念。合成事件在符合 W3C 规范定义的前提下,抹平浏览器之间的差异化表现。并且简化事件逻辑,对关联事件进行合成。如每当表单类型组件的值发生改变时,都会触发 onChange 事件,而 onChange 事件由 change、click、input、keydown、keyup 等原生事件组成。

知识点深入

  1. 原生事件和合成事件
    JavaScript 通过事件可以和 DOM 进行交互。

    1.1 原生事件
    主流浏览器基于 DOM2、DOM3 规范,实现标准化 DOM 事件。基于 Event 实现了浏览器中常见的用户事件如 UIEvent、InputEvent、MouseEvent 等。

    在事件发生时,相关信息会存储在 Event 的实例对象中,对象包含 currentTarget、detail、target、preventDefault()、stopPropagation() 等属性和方法。DOM 节点可以通过 addEventListener 和 removeEventListener 来添加或移除事件监听函数。

    // Event 属性
    boolean bubbles
    boolean cancelable
    DOMEventTarget currentTarget
    boolean defaultPrevented
    number eventPhase
    boolean isTrusted
    void preventDefault()
    void stopPropagation()
    void stopImmediatePropagation()
    DOMEventTarget target
    number timeStamp
    string type

    1.2 React 合成事件
    React 的事件机制中,在遵循规范的前提下,引入新的事件类型:合成事件(SyntheticEvent)。基于合成事件实现了浏览器中常见的用户事件,并对事件进行规范化处理,使它们在不同浏览器中具有一致的属性。

    在事件发生时,相关信息会存储在 SyntheticEvent 的实例对象中,对象包含原生事件对象类似的属性。

    // SyntheticEvent 属性
    boolean bubbles
    boolean cancelable
    DOMEventTarget currentTarget
    boolean defaultPrevented
    number eventPhase
    boolean isTrusted
    DOMEvent nativeEvent
    void preventDefault()
    boolean isDefaultPrevented()
    void stopPropagation()
    boolean isPropagationStopped()
    void persist()
    DOMEventTarget target
    number timeStamp
    string type

    但是合成事件与原生事件不是一一映射的关系。比如 onMouseEnter 合成事件映射原生 mouseout、mouseover 事件。React 通过 registrationNameDependencies 来记录合成事件和原生事件的映射关系:

    /* Mapping from registration name to event name*/
    export const registrationNameDependencies = {
    onClick: [“click”],
    onMouseEnter: [“mouseout”, “mouseover”],
    onChange: [
    “change”,
    “click”,
    “focusin”,
    “focusout”,
    “input”,
    “keydown”,
    “keyup”,
    “selectionchange”,
    ],
    // …
    };

  2. React 事件机制
    2.1 React 事件的注册
    在这里插入图片描述
    使用 ReactDOM.createRoot 创建 Root 时,React 会调用 listenToAllSupportedEvents 方法对所有支持的原生事件进行监听:

    1. allNativeEvents 用于收集所有合成事件相关联的原生事件名。这个收集动作在事件插件初始化阶段完成;

      SimpleEventPlugin.registerEvents();
      EnterLeaveEventPlugin.registerEvents();
      ChangeEventPlugin.registerEvents();
      SelectEventPlugin.registerEvents();
      BeforeInputEventPlugin.registerEvents();
      
    2. 对每个原生事件调用 addTrappedEventListener 函数。该函数最终使用 addEventListener 方法,对原生事件进行捕获或冒泡阶段的事件监听注册。

      function addTrappedEventListener(targetContainer: EventTarget,domEventName: DOMEventName,eventSystemFlags: EventSystemFlags,isCapturePhaseListener: boolean) {let listener = createEventListenerWrapperWithPriority(targetContainer,domEventName,eventSystemFlags);// ...if (isCapturePhaseListener) {addEventCaptureListener(targetContainer, domEventName, listener);} else {addEventBubbleListener(targetContainer, domEventName, listener);}}
      

2.2 React 事件的触发
在这里插入图片描述
在注册事件阶段调用的 addTrappedEventListener 方法中,会使用 createEventListenerWrapperWithPriority 函数来创建事件回调。createEventListenerWrapperWithPriority 函数根据事件类型,划分出若干个不同优先级的 dispathEvent。事件回调最终都调用进 dispatchEvent 方法。

因此触发一个原生事件时,大致的执行流程如下:

  1. 原生事件触发后,进入 dispatchEvent 回调方法;
    attemptToDispatchEvent 方法根据该原生事件查找到当前原生 Dom 节点和映射的 Fiber 节点;
  2. 事件和 Fiber 等信息被派发给插件系统进行处理,插件系统调用各插件暴露的 extractEvents 方法;
  3. accumulateSinglePhaseListeners 方法向上收集 Fiber 树上监听相关事件的其他回调函数,构造合成事件并加入到派发队列 dispatchQueue 中;
  4. 调用 processDispatchQueue 方法,基于捕获或冒泡阶段的标识,按倒序或顺序执行 dispatchQueue 中的方法;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/522757.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

c++的STL(2)-- vector容器

目录 1. 默认构造 代码: 相关知识点: 2. 有参构造函数 以及 使用{}初始化对象 代码: 相关知识点: 3. vector容器在尾部添加和删除元素 代码: 使用push_back()和pop_back()进行尾部元素的添加和删除 相关知识点: 代码: 使用emplace_back在尾部添…

Unity插件之天气系统UniStorm

首先呢,它是一款强大的动态昼夜天气系统,能够以较快的帧速率创建AAA级动态生成的天气、照明和天空,并且具有300多个可定制的组件,允许用户创建任何可以想象的环境。 第一步:他需要两个物体Camera摄像机、Player播放器…

knife4j生产环境禁止打开页面

Knife4j是一个集Swagger2 和 OpenAPI3为一体的增强解决方案,官网地址:Knife4j 集Swagger2及OpenAPI3为一体的增强解决方案. | Knife4j 考虑到安全性问题,在实际服务部署到生产环境后就需要禁用到swagger页面的展示,这个时候只需…

报错:ModuleNotFoundError: No module named ‘tensorrt’

写在前面 我安装了tensorRT,在运行它自带的模型都没问题。 但是在代码中import tensorrt就报错: ModuleNotFoundError: No module named ‘tensorrt’。 网上搜了一大堆,发现是没有在自己的python环境下安装。 所以特意写这篇文章记录一下。 在进行下一…

继深圳后,重庆与鸿蒙展开原生应用开发合作

截至2023年底,开源鸿蒙开源社区已有250多家生态伙伴加入,开源鸿蒙项目捐赠人达35家,通过开源鸿蒙兼容性测评的伙伴达173个,累计落地230余款商用设备,涵盖金融、教育、智能家居、交通、数字政府、工业、医疗等各领域。 …

C++之创建与使用dll

目录 1、创建dll test.h test.cpp Source.def 2、使用dll testdll.cpp DLL,全称“Dynamic Link Library”,中文名为“动态链接库”,是一种在Windows操作系统中常见的库文件格式。它包含了可以由多个程序同时使用的代码和数据。与静态链接…

Docker安装主从数据库

我自己的主数据库名字 user_muster 密码是123456 从数据库 就是slave2 名字是root 密码是123456 首先开启docker后直接执行命令 docker run -d \ -p 3307:3306 \ -v /xk857/mysql/master/conf:/etc/mysql/conf.d \ -v /xk857/mysql/master/data:/var/lib/mysql \ -e MYSQL_…

瑞芯微 | I2S-音频基础 -1

最近调试音频驱动,顺便整理学习了一下i2s、alsa相关知识,整理成了几篇文章,后续会陆续更新。 喜欢嵌入式、Li怒晓得老铁可以关注一口君账号。 1. 音频常用术语 名称含义ADC(Analog to Digit Conversion)模拟信号转换…

OpenCASCADE+Qt创建建模平台

1、建模平台效果 2、三维控件OCCWidget 将V3d_View视图与控件句柄绑定即可实现3d视图嵌入Qt中&#xff0c;为了方便也可以基于QOpenGLWidget控件进行封装&#xff0c;方便嵌入各种窗体使用并自由缩放。 #ifndef OCCTWIDGET_H #define OCCTWIDGET_H#include <QWidget> #i…

FFmpeg教程(干货快速上手)

什么是FFmpeg&#xff1f; FFmpeg是一款免费、开源的跨平台多媒体处理工具&#xff0c;它支持几乎所有的视频格式和编码标准。FFmpeg包含了一系列的子项目和工具&#xff0c;如ffmpeg命令行工具用于转码和处理视频和音频文件&#xff0c;ffplay用于播放多媒体内容&#xff0c;…

Python学习笔记 -- 基础语法篇

目录 一. 数据类型 二. 注释 三. 输入输出及强制类型转换 3.1 print和input 3.2 强制类型转换 四. 运算符 4.1 算数运算符 4.2 比较运算符 4.3 逻辑运算符 五. 多元赋值 六. 条件语句 七. 循环语句 7.1 while循环 7.2 for循环 7.3 continue和break 一. 数据类型 …

人工智能|机器学习——k-近邻算法(KNN分类算法)

1.简介 k-最近邻算法&#xff0c;也称为 kNN 或 k-NN&#xff0c;是一种非参数、有监督的学习分类器&#xff0c;它使用邻近度对单个数据点的分组进行分类或预测。虽然它可以用于回归问题&#xff0c;但它通常用作分类算法&#xff0c;假设可以在彼此附近找到相似点。 对于分类…