为什么反应事件侦听器正在保存状态?

贡萨洛孔德索

所以我有这个反应功能组件:

export default function Login() {

    const [loginData, setLoginData] = useState<Credentials>({ email: "", password: "" })

    useEffect(() => {
        document.addEventListener('keydown', handleKeyDown)
        return () =>
            document.removeEventListener('keydown', handleKeyDown)
    }, [])

    function handleKeyDown(event: any) {
        if (event.key === "Enter")
            confirm()
    }

    function confirm() {
        httpPut<Credentials, void>("user/login", loginData).then(
            res => {
                var authorization = res.headers.authorization
                const parsed = jwt_decode(authorization)
                console.log(parsed)
            },
            err => {
                console.log(err)
            }
        )
    }
 return ...

}

我遇到了一些奇怪的行为,至少据我所知。我为 enter 键添加事件侦听器的 useEffect 正在保存 loginData 的状态。我的意思是,如果我填写输入并单击按钮,一切正常,但是当我单击回车键时,(我在我的 axios 请求中放置了一个 console.log 以便它记录数据)它来了{ email: "", password: "" }现在,通过尝试 arround,我设法通过添加 loginData 作为 useEffect 的依赖项来修复它,如下所示:

    useEffect(() => {
        document.addEventListener('keydown', handleKeyDown)
        return () =>
            document.removeEventListener('keydown', handleKeyDown)
    }, [loginData])

但这应该发生吗?这不是我第一次使用 React,而且我总是在 useEffect 中添加没有依赖关系的侦听器。对我来说,这似乎很奇怪,它有点“保存”事件侦听器本身的 loginData 状态。知道为什么会这样吗?或者即使它应该这样做?我让它工作,但我想知道为什么。

AKX

你看到了一个陈旧的闭包(一个像 React hooks 一样古老的故事)。

  1. 一旦组件安装,效果就会运行。由于它有一个空的依赖数组,它不会再次运行。
  2. 效果函数关闭(捕获),容我们说,版本 1 handleKeyDown
  3. 版本 1handleKeyDown结束于版本 1 confirm
  4. 版本 1confirm关闭了 的初始状态loginData(因为你应该替换诸如对象或数组之类的状态原子,而不是在内部改变它们以便 React 可以看到更改,所以原始对象仍然是封闭的)。
  5. 当状态原子loginData发生变化时,会创建新版本的confirmhandleKeyDown1. 这就是为什么该事件处理程序看到原始版本loginData以及为什么设置loginData为依赖项可以解决问题(因为它会导致新版本handleKeyDownconfirm用于事件)。

您的选择或多或少是:

  • loginData你一样依赖效果。这将导致无关的事件处理程序取消订阅/订阅周期,但这些可能不是性能问题。
  • 使整个功能链useCallback编辑,因此它们仅在必要时更新。不过,这或多或少是上述情况。
  • 使用 ref 来“装箱” loginData(例如useLatesthook)的最新状态,并在您的函数中使用该装箱的 ref confirm,即loginDataRef.current. 由于confirm仅关闭 ref (这是一个包含可变引用的“框”)而不是 over loginDataRef.current,因此访问current将始终获得最新状态。
  • confirm像上面一样,使用ref 将最新版本confirmRef.current()confirm.

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

反应导航焦点事件侦听器返回旧状态

为什么在注册事件侦听器并触发事件侦听器之前调用滚动事件?

为什么更新状态未反映在事件侦听器中:React Native,Hooks

事件侦听器DOMNodeInserted被多次运行,为什么?

为什么事件侦听器无法读取属性?

为什么mousedown事件侦听器通过函数运行?

反应流和事件侦听器之间有什么区别?

在更新 Audio 元素中的 `src` 后,事件侦听器会发生什么?(反应)

反应。如何在创建的侦听器中删除事件侦听器?

在 Firestore onSnapshot 侦听器中访问反应状态的问题

为什么侦听器列表是列表?

如何避免重复的事件侦听器做出反应?

从滚动事件侦听器反应setState挂钩

反应本机取消订阅事件侦听器

从javascript事件侦听器内部反应访问道具

取消订阅事件侦听器反应挂钩

删除事件侦听器手动做出反应

读取事件侦听器未在本机反应中触发

反应useEffect不清除事件侦听器

如何从正在卸载的背景中删除事件侦听器?

使用事件侦听器进行反应的自定义钩子在更新状态时不起作用

React:与事件侦听器相关的批处理状态更新

状态未按预期在事件侦听器之间更新

canvas事件侦听器切换参数状态

基于 Redux 状态更改的 React 事件侦听器

网络的 Lottie 事件侦听器和状态 - javascript

为什么此侦听器无法检测到窗口关闭事件?

使用事件侦听器检测更改时,为什么图标类没有更改?

为什么第二个事件侦听器不触发?