useState中的变量未在useEffect回调中更新

Abh*_*gal 5 javascript reactjs react-hooks use-effect

使用useState和useEffect挂钩时出现问题

import { useState, useEffect } from "react";

const counter = ({ count, speed }) => {
    const [inc, setInc] = useState(0);

    useEffect(() => {

        const counterInterval = setInterval(() => {
            if(inc < count){
                setInc(inc + 1);
            }else{
                clearInterval(counterInterval);
            }
        }, speed);

    }, [count]);

    return inc;
}

export default counter;
Run Code Online (Sandbox Code Playgroud)

上面的代码是一个计数器组件,它需要用props进行计数,然后用0初始化inc并递增它直到等于count

问题是我每次获得0时,都没有在useEffect和setInterval的回调中获得inc的更新值,因此它将inc呈现为1,而setInterval却永远不会清除。我认为inc必须在useusefffect和setInterval的回调函数的结尾处,所以我必须在那儿获得update inc,所以这可能是一个错误吗?

我不能在依赖项中传递inc(在其他类似问题中建议),因为在我的情况下,我在useEffect中设置了setInterval,因此在依赖项数组中传递inc会导致无限循环

我有一个使用有状态组件的有效解决方案,但是我想使用功能组件来实现

hel*_*joe 11

有几个问题:

  1. 你没有返回一个函数useEffect来清除间隔
  2. 您的inc值不同步,因为您没有使用 的先前值inc

一种选择:

const counter = ({ count, speed }) => {
    const [inc, setInc] = useState(0);

    useEffect(() => {
        const counterInterval = setInterval(() => {
            setInc(inc => {
                if(inc < count){
                    return inc + 1;
                }else{
                    // Make sure to clear the interval in the else case, or 
                    // it will keep running (even though you don't see it)
                    clearInterval(counterInterval);
                    return inc;
                }
            });
        }, speed);

        // Clear the interval every time `useEffect` runs
        return () => clearInterval(counterInterval);

    }, [count, speed]);

    return inc;
}
Run Code Online (Sandbox Code Playgroud)

另一种选择是包含inc在 deps 数组中,这使事情变得更简单,因为您不需要使用以前的incinside setInc

const counter = ({ count, speed }) => {
    const [inc, setInc] = useState(0);

    useEffect(() => {
        const counterInterval = setInterval(() => {
            if(inc < count){
                return setInc(inc + 1);
            }else{
                // Make sure to clear your interval in the else case,
                // or it will keep running (even though you don't see it)
                clearInterval(counterInterval);
            }
        }, speed);

        // Clear the interval every time `useEffect` runs
        return () => clearInterval(counterInterval);

    }, [count, speed, inc]);

    return inc;
}
Run Code Online (Sandbox Code Playgroud)

甚至还有第三种更简单的方法:包含inc在 deps 数组中,如果inc >= count在调用之前提前返回setInterval

    const [inc, setInc] = useState(0);

    useEffect(() => {
        if (inc >= count) return;

        const counterInterval = setInterval(() => {
          setInc(inc + 1);
        }, speed);

        return () => clearInterval(counterInterval);
    }, [count, speed, inc]);

    return inc;
Run Code Online (Sandbox Code Playgroud)