简体   繁体   English

Function 未使用挂钩指向 state 变量的更新值

[英]Function not pointing to the updated value of state variable using hooks

I am currently refactoring a react app from setState to hooks.我目前正在重构一个从 setState 到 hooks 的 React 应用程序。 I can't understand why the state variables aren't changed.我不明白为什么 state 变量没有改变。 Here is an example:这是一个例子:

import React, { useState, useEffect } from 'react';

function Hook() {
    const [num, setNum] = useState(1);

    useEffect(() => {
        window.addEventListener("mousemove", logNum);
    }, []);

    const logNum = () => {
        console.log(num);
    }
    const handleToggle = () => {
        if (num == 1) {
            console.log('setting num to 2');
            setNum(2);
        } else {
            console.log('setting num to 1');
            setNum(1);
        }
    }

    return (
        <div>
            <button onClick={handleToggle}>TOGGLE BOOL</button>
        </div>
    );
}
export default Hook;

When i click the button, I was expecting the output to be something like:当我点击按钮时,我期待 output 是这样的:

// 1
// setting num to 2
// 2
// setting num to 1
// 1

But the output look like this:但是 output 看起来像这样:

在此处输入图像描述

Why is the updated num variable not logged?为什么没有记录更新的 num 变量? Shouldn't the logNum() function always point to the current value of the state? logNum() function 不应该总是指向 state 的当前值吗?

That's why effect dependencies have to be exhaustive .这就是为什么效果依赖性必须是详尽无遗的。 Don't lie about dependencies . 不要在依赖关系上撒谎

logNum closures over num , so on every rerender there is a new num variable containing the new value, and a new logNum function logging that value. logNumnum上关闭,因此在每次重新渲染时都有一个包含新值的新num变量,以及一个记录该值的新logNum function。 Your effect however gets initialized only once, thus it only knows the first logNum .然而,您的效果只被初始化一次,因此它只知道第一个logNum Therefore, you have to add logNum as a dependency, so that the effect gets updated whenever num and thus logNum changes:因此,您必须添加logNum作为依赖项,以便在numlogNum发生变化时更新效果:

 useEffect(() => {
    window.addEventListener("mousemove", logNum);
}, [logNum]);

You'll notice that your effect does not correctly clean up , you should add a removeEventListener too.您会注意到您的效果没有正确清理,您也应该添加一个removeEventListener

    return () => window.removeEventListener("mousemove", logNum);

Now if you debug this piece of code, you'll notice that the effect triggers on every rerender.现在,如果您调试这段代码,您会注意到效果会在每次重新渲染时触发。 That is because a new logNum function gets created on every rerender, no matter wether num changes or not.这是因为在每次重新渲染时都会创建一个新的logNum function,无论num是否发生变化。 To prevent that, you can useuseCallback to make the logNum reference stable:为防止这种情况,您可以使用useCallback使logNum引用稳定:

  const logNum = useCallback(() => console.log(num), [num]);

An alternative to all of this would be to use a reference to the current state :所有这些的替代方法是使用对当前 state的引用:

  const actualNum = useRef(num);

    // that works no matter when and how this is executed
    console.log(actualNum.current);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM