useState 中的变量未在 useEffect 回调中更新 [英] variable in useState not updating in useEffect callback
问题描述
我在使用 useState 和 useEffect 钩子时遇到问题
I'm having an issue while using useState and useEffect hooks
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;
上面的代码是一个计数器组件,它在 props 中取 count,然后用 0 初始化 inc 并递增它直到它等于 count
Above code is a counter component, it takes count in props, then initializes inc with 0 and increments it till it becomes equal to count
问题是每次我得到 0 时,我都没有在 useEffect 和 setInterval 的回调中得到 inc 的更新值,所以它将 inc 呈现为 1 并且 setInterval 永远不会清楚.我认为 inc 必须关闭 useEffect 和 setInterval 的回调,所以我必须在那里获取更新 inc,所以也许这是一个错误?
The issue is I'm not getting the updated value of inc in useEffect's and setInterval's callback every time I'm getting 0, so it renders inc as 1 and setInterval never get clear. I think inc must be in closure of use useEffect's and setInterval's callback so I must get the update inc there, So maybe it's a bug?
我不能在依赖中传递 inc(在其他类似问题中建议),因为就我而言,我在 useEffect 中设置了 setInterval,因此在依赖数组中传递 inc 会导致无限循环
I can't pass inc in dependency ( which is suggested in other similar questions ) because in my case, I've setInterval in useEffect so passing inc in dependency array is causing an infinite loop
我有一个使用有状态组件的工作解决方案,但我想使用功能组件来实现这一点
I have a working solution using a stateful component, but I want to achieve this using functional component
推荐答案
有几个问题:
- 您没有从
useEffect
返回一个函数来清除间隔 - 您的
inc
值不同步,因为您没有使用inc
的先前值.
- You're not returning a function from
useEffect
to clear the interval - Your
inc
value is out of sync because you're not using the previous value ofinc
.
一种选择:
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
,这使事情变得更简单,因为您不需要在 setInc中使用之前的
inc
代码>:
Another option is to include inc
in the deps array, this makes things simpler since you don't need to use the previous inc
inside 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;
}
甚至还有更简单的第三种方式:在 deps 数组中包含 inc
,如果 inc >= count
,则在调用 setInterval
之前提前返回:
There's even a third way that's even simpler:
Include inc
in the deps array and if inc >= count
, return early before calling 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;
这篇关于useState 中的变量未在 useEffect 回调中更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!