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 中处理事件更加方便和跨浏览器兼容,并且提供了一致的事件处理机制。

相关推荐
刺客-Andy4 小时前
React第四节 组件的三大属性之state
前端·javascript·react.js
黄毛火烧雪下5 小时前
React 表单Form 中的 useWatch
前端·javascript·react.js
独上归州8 小时前
Vue与React的Suspense组件对比
前端·vue.js·react.js·suspense
秦时明月之君临天下10 小时前
React和Next.js的相关内容
前端·javascript·react.js
米奇妙妙wuu11 小时前
React中 setState 是同步的还是异步的?调和阶段 setState 干了什么?
前端·javascript·react.js
李刚大人11 小时前
react-amap海量点优化
前端·react.js·前端框架
GISer_Jing1 天前
React核心功能详解(一)
前端·react.js·前端框架
FØund4041 天前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
疯狂的沙粒1 天前
如何在 React 项目中应用 TypeScript?应该注意那些点?结合实际项目示例及代码进行讲解!
react.js·typescript
鑫宝Code1 天前
【React】React Router:深入理解前端路由的工作原理
前端·react.js·前端框架