当前位置: 首页 > article >正文

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

发现宝藏

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


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

1. 事件绑定方式

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

    <button id="myButton">Click Me</button>
    <script>
      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.kler.cn/a/446825.html

相关文章:

  • StarRocks:存算一体模式部署
  • MacPorts 中安装高/低版本软件方式,以 RabbitMQ 为例
  • 【原生js案例】让你的移动页面实现自定义的上拉加载和下拉刷新
  • SAP RESTful架构和OData协议
  • CPU性能优化--函数分组
  • git使用和gitlab部署
  • 源码编译llama.cpp for android
  • linux下网络编程socketselectepoll的底层实现原理
  • js常用方法之: 预览大图(uniapp原生方法封装)
  • 机器学习《西瓜书》学习笔记《待续》
  • git分支管理及策略
  • HIPT论文阅读
  • Java 优化springboot jar 内存 年轻代和老年代的比例 减少垃圾清理耗时 如调整 -XX:NewRatio
  • 使用ResNet18进行猫狗分类(原始数据处理+训练流程)
  • Android Overlay Priority Rules
  • Oracle 数据库函数的用法(一)
  • Java-30 深入浅出 Spring - IoC 基础 启动IoC 纯XML启动 Bean、DI注入
  • [react]5、React脚手架
  • 【Linux】文件IO--open/close/文件描述符(详)
  • 【技术干货】移动SDK安全风险及应对策略
  • 【WPS安装】WPS编译错误总结:WPS编译失败+仅编译成功ungrib等
  • 在 Ubuntu 下通过 Docker 部署 MariaDB 服务器
  • 2024.12.18 周三
  • 对 MYSQL 架构的了解
  • PySide6如何使用自定义委托实现在TableWidget填充颜色
  • CTF 伪造ip的http请求头(学习记录)