反应合成事件

2025-06-07

反应合成事件

我想要一个新的开始😇

React
一个用于构建生动闪亮的用户界面的 JavaScript 库🥰。

事件
用户与应用程序交互的不同方式,例如点击、鼠标悬停、输入……等

合成
它是一个...🤔让我们首先了解 React 如何处理事件。

React 在文档级别监听每一个事件,在从浏览器接收到事件后,React 会用一个与原生浏览器事件具有相同接口的包装器来包装这个事件,这意味着我们仍然可以使用像这样的方法preventDefault()

那么为什么需要这个包装呢?!😏

想象一下这样的情况:同一个事件在不同的浏览器中有不同的名称。

想象一下当用户眨眼时触发的事件😉,这个事件在 chrome 中称为A,在 Safari 中称为B,在这种情况下,我们需要为每个浏览器做出不同的实现😵。

这个包装器所做的就是为同一个事件效果注册所有不同的名称,在我们的例子中是眨眼,只有一个名称,所以当我们想要监听眨眼效果而不是监听chrome 的A和Safari 的B时,我们只需使用onWink,这是 React 围绕真实事件创建的包装器。

因此,每当我们在 React 组件中触发事件时,我们实际上并不是在处理真正的 DOM 事件,而是在处理 React 的自定义事件类型,即合成事件

现在闭上你的眼睛😴,但不是这种闭法😅,在你的记忆中回忆起你曾经在 React 组件中使用过的所有 onClick(s)、onBlur(s)、onChange(s),这些都不是真正的事件,这些是 React 的合成事件😇。

因此我们不必再考虑不同浏览器的实现,React 使得创建跨浏览器应用程序变得不再那么痛苦,这意味着我们可以更加专注于将浏览器前缀添加到我们的 CSS 属性😅。

事情还没完,这还不是 React 合成事件的唯一亮点😃。合成事件的另一个引人注目的好处是,React 可以通过池化来重用这些事件对象,从而提升性能。

一旦调用事件处理程序,事件处理程序就是在触发事件后执行的方法,此事件对象上的所有属性将变为无效,设置为空/默认状态,以备再次重用。

到目前为止,一切看起来都很棒,您可能会感觉🧐,但一旦您看到警告:出于浏览器性能原因,此合成事件被重复使用,您可能还会经历一些🤨、🙄甚至😤的时刻。

让我们大多数人经历🤨、🙄和😤时刻的原因不是尽管有红色警告,但实际上是访问事件处理函数中的任何事件属性都失败了

想象一下:

import React, { useState } from "react"

const ExampleComponent = (() => {
  const [counter, setCounter] = useState()

  function handelArrowBtn(event) {
    if (event.keyCode === 40) { //down arrow button
      setCounter(counter - 1)
    } else if (event.keyCode === 38) { // up arrow button
      setCounter(counter + 1)
    }
  }

  return (
    <div>
      <input
        type="number"
        value={counter}
        onKeyDown={handelArrowBtn}
       />
    </div>
  )
})

export default ExampleComponent
Enter fullscreen mode Exit fullscreen mode

这个计数器既不会增加也不会减少。我们可爱的红色警告将会打印在浏览器控制台中。

让我们看看这里发生了什么……

handelArrowBtn()在我们的例子中,在事件处理函数被调用之后,我们的合成事件的对象(onKeyDown在我们的例子中)被无效,该对象内的键的旧值不再存在,事件对象返回到其原始状态以准备被重用,并且因为这是一个对象,所以我们handelArrowBtn()可以通过引用访问它,这意味着我们的函数现在可以访问具有其原始状态(无效版本)的事件对象。

那么,我们该如何解决这个问题呢?😯

其实,这个问题可以通过多种方式解决:

  • 存储我们需要的事件属性
function handelArrowBtn(event) {
  let keyCode = event.keyCode
  if (keyCode === 40) {
    setCounter(counter - 1)
  } else if (keyCode === 38) {
    setCounter(counter + 1)
  }
}
Enter fullscreen mode Exit fullscreen mode

或者我们也可以将所需的属性作为参数传递给事件处理函数,而不是直接从函数访问它

return (
    <div>
      <input
        type="number"
        value={counter}
        onKeyDown={(e) => handelArrowBtn(e.keyCode)}
      />
    </div>
  )
Enter fullscreen mode Exit fullscreen mode
  • 使用event.persist()它将从池中删除合成事件,这使我们能够在代码中访问事件对象属性
function handelArrowBtn(event) {
   event.persist()
   if (event.keyCode === 40) { 
      setCount(count - 1)
    } else if (event.keyCode === 38) {
      setCount(count + 1)
    }
  }
Enter fullscreen mode Exit fullscreen mode

希望以上内容对您有所帮助,感谢您的阅读。如果您有任何问题或想让我写一些主题,我很乐意为您提供帮助❤️。

文章来源:https://dev.to/smileycode/react-synthetic-events-34e5
PREV
JavaScript var、let 和 const
NEXT
TypeScript 类型保护和类型谓词