代码之家  ›  专栏  ›  技术社区  ›  Pontus Sandberg

函数没有使用钩子指向状态变量的更新值

  •  0
  • Pontus Sandberg  · 技术社区  · 4 年前

    我目前正在将react应用程序从setState重构为hooks。我不明白为什么状态变量没有改变。举个例子:

    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;
    

    当我单击按钮时,我希望输出类似于:

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

    但输出结果如下:

    enter image description here

    为什么没有记录更新的num变量? logNum()函数不应该总是指向状态的当前值吗?

    1 回复  |  直到 4 年前
        1
  •  2
  •   Jonas Wilms    4 年前

    这就是为什么效果依赖必须是 详尽的 . Don't lie about dependencies

    logNum 关闭 num 所以每次重播都会有一个新的 号码 包含新值的变量,以及 函数记录该值。但是你的效果只初始化一次,因此它只知道第一次 对数 . 因此,您必须添加 号码 对数 变化:

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

    clean up ,您应该添加 removeEventListener

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

    现在,如果您调试这段代码,您将注意到效果会在每个rerender上触发。那是因为一个新的 对数 号码 是否改变。为了防止这种情况,你可以使用 useCallback 使 对数

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

    除此之外的另一种方法是使用 current state

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