React中合成事件

在 React 中,合成事件是一个封装了 底层浏览器原生事件跨浏览器包装对象

底层的浏览器原生事件对象

  • type:事件的类型,例如 "click"、"keydown" 等。
  • target:触发事件的目标元素。
  • currentTarget:当前正在处理事件的元素(可能是目标元素的祖先元素)。
  • eventPhase:事件所处的阶段,捕获阶段(1)、目标阶段(2)或冒泡阶段(3)。
  • timeStamp:表示事件发生的时间戳。
  • preventDefault():用于取消事件的默认行为。
  • stopPropagation():用于停止事件在 DOM 树中的传播。
  • 鼠标事件对象可能包含鼠标坐标信息(如 clientXclientY
  • 键盘事件对象可能包含按下的键码(如 keyCodekey)等
  • 底层浏览器原生事件对象的结构和属性可能因浏览器而异,不同浏览器可能会有一些差异。React 的合成事件对象封装了这些底层浏览器原生事件对象,提供了一致的跨浏览器接口和属性

React 使用合成事件来提供一致性跨浏览器兼容性,并且使事件处理更加方便。

在 React 中,合成事件是通过事件委托(event delegation)的方式实现的。React 通过在最外层的 DOM 节点上添加事件监听器来捕获所有事件,并使用统一的方式构建并分发合成事件对象。

以下是 React 实现合成事件的大致步骤:

  1. 当你在 JSX 元素上定义一个事件处理函数(例如 onClick),React 将创建一个合成事件对象。
  2. React 使用原生事件监听机制将事件绑定到最外层的 DOM 节点上,而不是将事件绑定到每个具体的元素上。
  3. 当事件触发时,浏览器会将原生事件传递给最外层的 DOM 节点。
  4. React 在捕获阶段接收到原生事件后,根据事件类型和目标元素等信息构建合成事件对象。这个合成事件对象是一个普通的 JavaScript 对象,它封装了底层浏览器原生事件的属性和方法。
  5. 合成事件对象被传递给对应的事件处理函数,你可以在处理函数中访问合成事件对象的属性和方法,就像处理原生事件一样。

React 的合成事件对象包含了与原生事件类似的常用属性,如 targetcurrentTargettypepreventDefault()stopPropagation() 等。此外,React 还提供了一些额外的属性和方法,以提供更多功能和跨浏览器兼容性。

需要注意的是,React 并没有为每个事件都创建一个新的合成事件对象。相反,它使用了一个事件池(Event Pool)来重用已经存在的合成事件对象,以减少内存分配的开销。当事件处理函数执行完成后,合成事件对象会被重置,并返回到事件池中等待下次使用。

React 在内部维护了一个事件池,该事件池是一个数组,用于存储可重用的合成事件对象。

// 复制代码
const eventPool = [];

function createSyntheticEvent(nativeEvent) {
  // 如果事件池中有可重用的合成事件对象,则从池中取出并重置
  if (eventPool.length > 0) {
    const recycledEvent = eventPool.pop();
    recycledEvent.nativeEvent = nativeEvent;
    return recycledEvent;
  }

  // 如果事件池为空,则创建新的合成事件对象
  return {
    nativeEvent,
    target: nativeEvent.target,
    currentTarget: nativeEvent.currentTarget,
    type: nativeEvent.type,
    // 其他属性和方法...
  };
}

function resetSyntheticEvent(syntheticEvent) {
  // 重置合成事件对象的属性
  syntheticEvent.nativeEvent = null;
  syntheticEvent.target = null;
  syntheticEvent.currentTarget = null;
  syntheticEvent.type = null;
  // 重置其他属性...

  // 将合成事件对象放回事件池中
  eventPool.push(syntheticEvent);
}

当事件触发时,React 从事件池中取出一个空闲的合成事件对象,并将原生事件的属性拷贝到该对象中,以构建完整的合成事件对象。然后,React 将这个合成事件对象传递给事件处理函数。

在事件处理函数执行完成后,React 会清空合成事件对象的属性,并将其标记为空闲状态,然后将其放回事件池中,以便下次使用。这样就实现了合成事件对象的重用。

通过重用合成事件对象,React 避免了为每个事件都创建新的对象,从而节省了内存分配和垃圾回收的开销。这对于大量频繁触发事件的应用程序来说尤为重要,可以显著提高性能。

需要注意的是,由于合成事件对象被重用,因此在异步操作中访问合成事件对象的属性是不安全的,因为它们可能已经被重置或复用。如果你需要在异步操作中访问合成事件的属性,请将需要访问的属性保存到变量中,并在异步操作中使用该变量来获取正确的值。

总结一下,React 使用事件池来重用已经存在的合成事件对象,以减少内存分配的开销。它从事件池中获取空闲的合成事件对象,并在事件触发时将原生事件的属性拷贝到该对象中。处理完成后,合成事件对象被清空并放回事件池中等待下次使用。这种优化机制可以提高性能并减少内存消耗。

通过这种方式,React 实现了一套统一的、跨浏览器的事件系统,使得事件处理在不同浏览器中具有一致的行为,并提供了高效的性能优化机制。

合成事件与原生事件类似,但有一些区别:

  1. 跨浏览器兼容性:合成事件在不同浏览器之间提供了一致的行为,避免了常见的浏览器差异。这样你就不必担心编写针对特定浏览器的代码。
  2. 事件池:React 使用事件池来管理合成事件,以减少内存分配的开销。当事件处理函数执行完成后,合成事件将被重置并返回到池中等待下次使用。这意味着你不能在异步操作中访问合成事件的属性,因为它们可能已经被重置或复用。
  3. 事件委托:React 使用事件委托来处理所有组件上的事件监听。这意味着你可以在父组件上定义事件处理函数,然后通过 props 将其传递给子组件,而无需在每个子组件上单独设置事件监听。

使用合成事件的语法与原生事件相似,在 JSX 元素中使用驼峰式命名的事件属性,例如 onClickonSubmit 等。事件处理函数接收一个合成事件对象作为参数,你可以通过访问该对象的属性来获取有关事件的信息。

以下是一个示例,展示了如何在 React 中使用合成事件:

scala 复制代码
class MyComponent extends React.Component {
  handleClick = (event) => {
    console.log(event.target); // 获取事件目标元素
  }

  render() {
    return <button onClick={this.handleClick}>Click me</button>;
  }
}

需要注意的是,由于合成事件是 React 提供的封装层,与原生事件存在一些细微差异。大多数情况下,这些差异不会对开发产生重大影响,但在某些特殊情况下可能需要考虑到它们(例如,在某些情况下,使用 event.nativeEvent 可以访问底层原生事件对象)。

总之,合成事件使得在 React 中处理事件更加方便和跨浏览器兼容,并且提供了一致的事件处理机制。

相关推荐
吕彬-前端3 小时前
使用vite+react+ts+Ant Design开发后台管理项目(二)
前端·react.js·前端框架
小白小白从不日白3 小时前
react hooks--useCallback
前端·react.js·前端框架
恩婧3 小时前
React项目中使用发布订阅模式
前端·react.js·前端框架·发布订阅模式
程序员小杨v14 小时前
如何使用 React Compiler – 完整指南
前端·react.js
谢尔登6 小时前
Babel
前端·react.js·node.js
卸任6 小时前
使用高阶组件封装路由拦截逻辑
前端·react.js
清汤饺子8 小时前
实践指南之网页转PDF
前端·javascript·react.js
霸气小男9 小时前
react + antDesign封装图片预览组件(支持多张图片)
前端·react.js
小白小白从不日白9 小时前
react 组件通讯
前端·react.js
小白小白从不日白11 小时前
react hooks--useReducer
前端·javascript·react.js