Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/478.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript useState中的变量未在useEffect回调中更新_Javascript_Reactjs_React Hooks_Use Effect - Fatal编程技术网

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

Javascript useState中的变量未在useEffect回调中更新,javascript,reactjs,react-hooks,use-effect,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(() => {

我在使用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;
从“react”导入{useState,useffect};
常量计数器=({count,speed})=>{
const[inc,setInc]=useState(0);
useffect(()=>{
常量计数器间隔=设置间隔(()=>{
如果(包括<计数){
setInc(inc+1);
}否则{
净间隔(反间隔);
}
},速度);
},[计数];
返回公司;
}
导出默认计数器;
上面的代码是一个计数器组件,它在props中接受count,然后用0初始化inc并递增,直到它等于count

问题是每次我得到0时,我没有在useEffect和setInterval的回调中得到inc的更新值,因此它将inc呈现为1,而setInterval永远无法清除。我认为inc必须关闭useffect和setInterval的回调,所以我必须在那里获得更新inc,所以可能是一个bug

我不能在依赖项中传递inc(这在其他类似问题中建议),因为在我的例子中,我已经在useffect中设置了interval,所以在依赖项数组中传递inc会导致无限循环


我有一个使用有状态组件的工作解决方案,但我想使用功能组件来实现这一点。这里的问题是每次运行
useffect
时都会定义
count
更新时的
clearInterval
回调。定义时,
inc
的值是将在回调中读取的值

此编辑有不同的方法。我们包含一个ref,用于跟踪
inc
小于
count
,如果小于,我们可以继续递增
inc
。如果不是,那么我们清除计数器(正如您在问题中所做的)。每次
inc
更新时,我们都会评估它是否仍然小于count,并将其保存在
ref
中。然后在前面的
useffect
中使用此值

正如@DennisVash在他的回答中正确指出的那样,我包括了对速度的依赖

const useCounter = ({ count, speed }) => {
    const [inc, setInc] = useState(0);
    const inc_lt_count = useRef(inc < count);

    useEffect(() => {
        const counterInterval = setInterval(() => {
            if (inc_lt_count.current) {
                setInc(inc => inc + 1);
            } else {
                clearInterval(counterInterval);
            }
        }, speed);

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

    useEffect(() => {
        if (inc < count) {
            inc_lt_count.current = true;
        } else {
            inc_lt_count.current = false;
        }
    }, [inc, count]);

    return inc;
};
const useCounter=({count,speed})=>{
const[inc,setInc]=useState(0);
const inc_lt_count=useRef(inc{
常量计数器间隔=设置间隔(()=>{
如果(包括当前计数){
setInc(inc=>inc+1);
}否则{
净间隔(反间隔);
}
},速度);
return()=>clearInterval(计数器间隔);
},[计数,速度];
useffect(()=>{
如果(包括<计数){
inc_lt_count.current=true;
}否则{
inc_lt_count.current=false;
}
},[inc,count]);
返回公司;
};

需要处理的主要问题是根据道具情况确定的清理间隔

您应该在功能设置状态中添加条件检查:

setInc(inc => (inc < count ? inc + 1 : inc));

有几个问题:

  • 您没有从
    useffect
    返回函数来清除间隔
  • 您的
    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;
    }
    
    还有第三种更简单的方法: 在deps数组中包括
    inc
    ,如果
    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;
    

    对否决票有什么解释吗?尝试使用回调使用最新的值:
    setInc(inc=>inc+1)。如果有帮助,请告诉我。请告诉我们如何使用此挂钩,然后请注意,挂钩不能像useEffect需要
    speed
    inc
    作为依赖项那样简单,您应该返回一个函数来清除interval@Alvaro,我尝试使用setInc(inc=>inc+1);现在我在setInc的回调中得到更新的inc,但在setInterval的回调中仍然没有得到更新的inc,所以它永远不会进入else条件,从而导致无穷大loop@DennisVash谢谢你让我知道,你能详细说明为什么它不起作用吗?你检查过了吗?原因有很多,主要是增加引用不会导致重新渲染,在父组件(我使用计数器的地方)中,count的值来自服务器,这就是为什么我将其添加到依赖项数组中,我可以通过在API调用后装载计数器组件来移除其依赖项。因此,useEffect将作为componentDidMount工作。现在,使用useRef不会重新渲染组件。所以我需要状态来重新加载ComponentNC。当前值正在获取更新,但react不会重新加载它,因为它不在state@AbhaySehgal这就是我所说的“副作用”。因此,您需要在一个州内使用
    inc
    。好的,让我来编辑。这可能适用于这个特定的用例,但如果组件太频繁地重新呈现,会导致错误:您能重现任何错误吗?请尝试setInc函数中的console.log(),它调用infinitelyIt将一直运行到卸载,我想您想清除interval on条件,让我来修复it@AbhaySehgal我编辑了答案,现在它在计数条件下清除选项一:否则情况是返回inc,然后清除setInterval,这样该行将永远不会执行,并将导致无限循环所有选项都工作正常,感谢您的回答,如果应该返回setInc(inc+1),第二个选项中有一个问题
    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;
    }
    
        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;