React 事件机制和原生 DOM 事件流有什么区别

ops/2024/12/22 8:13:38/

发现宝藏

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。【宝藏入口】。


React 的事件机制与原生 DOM 事件流在设计和实现上有一些显著的区别。了解这些区别有助于我们更好地理解 React 是如何管理事件的,并且能更高效地使用它。

1. 事件绑定方式

  • 原生 DOM 事件流
    在原生 JavaScript 中,事件是通过直接绑定到 DOM 元素上实现的。例如:

    <button id="myButton">Click Me</button>
    <script>javascript">document.getElementById("myButton").addEventListener("click", function() {alert("Button clicked!");});
    </script>
    

    事件处理程序通过 addEventListeneronclick 等方式绑定到 DOM 元素上,且每个元素的事件监听器都是独立的。

  • React 事件机制
    React 的事件系统使用 事件委托 的方式,所有的事件处理程序都统一绑定到 根 DOM 元素(通常是 documentroot)。React 会使用一个单一的事件监听器来管理所有组件中的事件。这是为了提升性能,减少不必要的事件监听器数量。React 事件通过 合成事件系统(SyntheticEvent) 来处理。

    例如:

    function MyButton() {const handleClick = () => alert("Button clicked!");return <button onClick={handleClick}>Click Me</button>;
    }
    

    虽然在 JSX 中看起来像是直接在按钮上绑定了事件,但实际上,React 会将所有的事件处理程序集中到根节点,并且利用事件代理来处理事件。

2. 事件流(Event Flow)

事件流包括了三个阶段:捕获阶段(Capturing)、目标阶段(Target)和冒泡阶段(Bubbling)。

  • 原生 DOM 事件流
    原生 DOM 事件流采用的是 冒泡模型,即事件从目标元素开始向上传播到父元素,直到到达根节点。此外,原生 DOM 事件也支持 捕获阶段,即事件从根节点开始向下传播到目标元素。

    • 捕获阶段:事件从根节点开始向下到目标元素(先执行)。
    • 目标阶段:事件在目标元素上触发。
    • 冒泡阶段:事件从目标元素向上传播到根节点。

    你可以通过设置 addEventListener 的第三个参数来控制是使用冒泡阶段还是捕获阶段:

    element.addEventListener('click', handler, true);  // 捕获阶段
    element.addEventListener('click', handler, false); // 冒泡阶段
    
  • React 事件流
    React 默认只支持 冒泡阶段,不支持捕获阶段。React 的事件系统将所有事件处理程序都放在事件冒泡阶段执行,因此 React 中的事件会依次向上传播,直到到达根组件(一般是 documentroot)。React 不直接使用 DOM 的捕获和冒泡机制,而是通过合成事件系统来模拟类似的行为。

3. 事件对象(SyntheticEvent)

  • 原生 DOM 事件对象
    原生 DOM 事件对象是由浏览器创建的原生 JavaScript 对象,包含事件的详细信息,如 event.targetevent.type 等。该对象在事件处理函数中是直接由浏览器传递的。

  • React 合成事件(SyntheticEvent)
    React 在内部使用一个 合成事件系统(SyntheticEvent),它是对浏览器原生事件对象的包装。这个合成事件与原生事件对象有相同的接口(例如:event.targetevent.preventDefault() 等),但是它在 React 内部进行了封装,具有跨浏览器的兼容性。合成事件还可以减少内存泄漏的风险,因为它们在事件处理程序执行后会被池化(被重用),而不是每次都创建新的事件对象。

    示例:

    function MyButton() {const handleClick = (event) => {console.log(event);  // 这里的 event 是 SyntheticEvent};return <button onClick={handleClick}>Click Me</button>;
    }
    

4. 事件委托(Event Delegation)

  • 原生 DOM 事件委托
    在原生 DOM 中,事件委托是通过将事件监听器绑定到父元素来实现的,避免在每个子元素上单独绑定事件。例如:

    document.getElementById("parent").addEventListener("click", function(event) {if (event.target && event.target.matches("button")) {alert("Button clicked!");}
    });
    
  • React 事件委托
    React 默认实现了事件委托,它将所有的事件处理程序绑定到根元素,而不是每个组件的 DOM 元素上。React 通过事件代理的方式提高性能,避免为每个组件和 DOM 元素单独绑定事件监听器。React 会将事件处理委托到 document 或根节点上,再通过事件的传播机制处理到每个具体的事件。

5. 性能优化

  • 原生 DOM 事件
    原生 DOM 中,如果你在多个元素上添加事件监听器(如 addEventListener),每个元素都会有自己的事件监听器。这可能导致性能问题,尤其是当页面中有大量的元素时,因为每个元素都需要独立的事件监听器。

  • React 事件机制
    由于 React 使用了事件委托机制,所有的事件处理程序都被集中在一个单独的事件监听器上,这显著减少了事件监听器的数量,从而提升了性能。这是 React 事件系统的一大优势。

6. 事件池(Event Pooling)

  • 原生 DOM 事件
    原生事件对象会在每个事件触发时创建,事件处理函数执行后,这些事件对象会继续存在,直到垃圾回收机制处理它们。

  • React 合成事件池化
    在 React 中,事件对象是池化的,这意味着每次事件处理完成后,React 会将事件对象归还到事件池中,这样就可以复用这些对象,避免频繁的对象创建和销毁,从而提升性能。

总结

特性原生 DOM 事件React 事件机制
事件绑定直接绑定到 DOM 元素事件委托,统一绑定到根 DOM 元素
事件流捕获、目标、冒泡阶段只支持冒泡阶段
事件对象原生事件对象SyntheticEvent,包装后的事件对象
事件委托手动实现事件委托自动实现事件委托
性能优化每个元素独立绑定事件监听器通过事件委托优化性能
事件池没有池化机制合成事件池化,减少内存使用

React 的事件机制与原生 DOM 事件机制相比,主要通过事件委托、合成事件和池化机制等手段来提升性能和跨浏览器兼容性。它的设计旨在简化开发者的工作,使得在 React 中处理事件更加高效且一致。


http://www.ppmy.cn/ops/143973.html

相关文章

Android运行低版本项目可能遇到的问题

Android运行低版本项目可能遇到的问题 低版本项目总是遇到各种问题的&#xff0c;耐心点 一、gradle-xxx.xxx.xxx.zip一直下载不下来 在gradle-wrapper.properties可以试下 distributionBaseGRADLE_USER_HOME distributionPathwrapper/dists zipStoreBaseGRADLE_USER_HOME …

android:sharedUserId 应用进程声明介绍

背景 adb install 安装系统软件报错,原因是签名不一致,进程改变。 代码分析 AndroidManifest.xml 定义的 android:sharedUserId 应用归属进程不同,从phone切换到system。 初始配置 <manifest xmlns:android="http://schemas.android.com/apk/res/android"c…

Windows下安装Rabbit MQ

一、安装环境&#xff1a; 系统&#xff1a;windows11; 环境配置安装&#xff1a;otp_win64_25.3.2.14.exe&#xff08;erlang类库&#xff09;&#xff1b; 服务应用安装&#xff1a;rabbitmq-server-3.12.4.exe&#xff1b; 二、erlang环境&#xff1a; 1.执行…

关于electron项目运行时,只编译渲染进程,不编译主进程问题

现象 编译到此处卡住没有报错也没下文 看下命令执行后操作 找到对应命令后操作 这里的await 没有收到完成信号导致 再看vue-cli-service 命令 此处发现是这个方法报错导致 再看这个方法 结论 所以项目不能存在 yarn.lock 而去使用npm&#xff0c;vuecli会优先执行yarn 命令&a…

自动化测试工具Ranorex Studio(六十八)-如何加载Ranorex Module 到你的Flash 应用

如何加载Ranorex Module 到你的Flash 应用 1. 启动 Adobe Flash CS3/CS4/CS5 并且打开你的应用 2. 将下列代码添加到你的ACTIONS (按F9): 1. import flash.net.URLRequest; 2. var rxloader : Loader new Loader(); 3. stage.addChild(rxloader); 4. rxload…

数巅科技入选《数据治理产业图谱3.0》BSIM板块

近日&#xff0c;中国通信标准化协会大数据技术标准推进委员会发布了《数据治理产业图谱3.0》&#xff0c;数巅科技连续第二年入选该系列图谱&#xff0c;深厚的技术实力和行业落地实践能力再获权威认可。 数据是数字经济的重要生产要素&#xff0c;是企业数字化转型和数智化升…

win64_11gR2_database win10

win64_11gR2_database win10

网络编程 03:端口的定义、分类,端口映射,通过 Java 实现了 IP 和端口的信息获取

一、概述 记录时间 [2024-12-19] 前置文章&#xff1a; 网络编程 01&#xff1a;计算机网络概述&#xff0c;网络的作用&#xff0c;网络通信的要素&#xff0c;以及网络通信协议与分层模型 网络编程 02&#xff1a;IP 地址&#xff0c;IP 地址的作用、分类&#xff0c;通过 …