react18中的合成事件与浏览器中的原生事件

React 通过将事件 normalize 以让他们在不同浏览器中拥有一致的属性。

  • 合成事件

    SyntheticEvent 实例将被传递给你的事件处理函数,它是浏览器的原生事件的跨浏览器包装器。除兼容所有浏览器外,它还拥有和浏览器原生事件相同的接口,包括 stopPropagation() 和 preventDefault()。
    如果因为某些原因,当你需要使用浏览器的底层事件时,只需要使用 nativeEvent 属性来获取即可。合成事件与浏览器的原生事件不同,也不会直接映射到原生事件。例如,在 onMouseLeave 事件中 event.nativeEvent 将指向 mouseout 事件。每个 SyntheticEvent 对象都包含以下属性:

    js 复制代码
    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
js 复制代码
import { Component } from "react";
class ClassComp extends Component {
  state = {
    count: 10,
  };
  handleAdd = (e) => {
    this.setState({ count: this.state.count + 1 });
    console.log(e);
  };
  render() {
    const { count } = this.state;
    return (
      <div>
        Class Component
        <p>
          {count}
          <br />
          <button onClick={this.handleAdd}>add</button>
        </p>
      </div>
    );
  }
}
export default ClassComp;

SyntheticBaseEvent是对浏览器原生事件的一个封装,让不同的浏览器的 API 表现一致。浏览器常用的事件基本都有

  • 原生事件
html 复制代码
<body>
  <noscript>You need to enable JavaScript to run this app.</noscript>
  <div id="root"></div>
  <div id="box">
    <button id="btn">提交</button>
  </div>
  <script>
    window.onload = function () {
      const btn = document.getElementById("btn");
      btn.onclick = handleClick;
    };

    function handleClick(e) {
      console.log("🚀 ~ handleClick ~ e:", e);
      console.log("提交成功");
    }
  </script>
</body>
  • 是要方法经过 bind 处理,那么最后一个实参就是传递的合成事件对象。
js 复制代码
handleAdd = (x, e) => {
  console.log("🚀 ~ ClassComp ~ x:", x);
  console.log(e);
};
<button onClick={this.handleAdd.bind(null, 20)}>add</button>;
  • 直接使用箭头函数,获取事件对象和参数
js 复制代码
handleAdd2 = (e, x) => {
  console.log("🚀 ~ ClassComp ~ e, x:", e, x);
};
<button onClick={(e) => this.handleAdd2("10", e)}>add2</button>;

事件委托

利用事件的传播机制,将事件绑定到父元素上,通过判断目标元素来执行相应的事件。

传统方法是直接获取元素,然后绑定事件。

  • 事件的捕获和冒泡



  • 目标元素阻止冒泡

  • event.stopPropagation()在事件对象中,调用该方法将阻止事件(包括冒泡或捕获)在 DOM 中继续传播。

  • event.stopImmediatePropagation()在事件对象中,调用该方法其他未执行的方法也不会执行了

  • 最外层阻止冒泡,阻止事件继续向上传播

React 中合成事件的原理

  • 合成事件绝对不是直接给元素addEventListener进行事件的绑定,而是通过事件委托的方式,给 document 进行事件的绑定。
  • r17 之前的 React 内部通过事件池SyntheticEvent来统一处理浏览器兼容问题,并且将事件委托给 document,且只做了对冒泡阶段的委托。
  • 事件池SyntheticEvent是一个对象,用来包装原生事件。
  • r17 及以后版本,事件池SyntheticEvent是单例模式。都是委托给#root 这个容器,捕获和冒泡都做了委托
  • 事件池SyntheticEvent对象在事件池中缓存,当事件触发时,会从事件池中获取一个对象。
  • 对于没有事件传播机制的事件,才是单独做的事件绑定。例如,onMouseEnter,onMouseLeave,onFocus 等。
  • 在组件渲染的时候,如果发现有 onXxx,onXxxxCapture 这样的属性,不会直接给元素绑定事件,只是把该方法作为属性保存到组件的实例上。然后对#root 容易做了事件绑定。

React中合成事件的处理原理

在16版本中,合成事件的处理机制,不再是把事件委托给#root元素,而是委托给docunent元素,并且只做了冒泡阶段的委托:在委托的方法中,把onXxx/onMxxcaptare合成事件属性进行执行!
React16中,关于含成事件对象的处理,react内部是基于"事件对象池"做了一个缓存机制!react17及以后,是去掉了这套事件对象池和缓存机制的!

相关推荐
m0_7190841118 分钟前
React笔记张天禹
前端·笔记·react.js
Ziky学习记录32 分钟前
从零到实战:React Router 学习与总结
前端·学习·react.js
wuhen_n37 分钟前
JavaScript链表与双向链表实现:理解数组与链表的差异
前端·javascript
wuhen_n41 分钟前
JavaScript数据结构深度解析:栈、队列与树的实现与应用
前端·javascript
狗哥哥1 小时前
微前端路由设计方案 & 子应用管理保活
前端·架构
青青家的小灰灰1 小时前
React 19 核心特性与版本优化深度解析
react.js
前端大卫2 小时前
Vue3 + Element-Plus 自定义虚拟表格滚动实现方案【附源码】
前端
却尘2 小时前
Next.js 请求最佳实践 - vercel 2026一月发布指南
前端·react.js·next.js
ccnocare2 小时前
浅浅看一下设计模式
前端
Lee川2 小时前
🎬 从标签到屏幕:揭秘现代网页构建与适配之道
前端·面试