Javascript SetInterval未显示更新状态
在调用Javascript SetInterval未显示更新状态,javascript,reactjs,setinterval,react-hooks,Javascript,Reactjs,Setinterval,React Hooks,在调用setInterval函数之前,我已将状态设置为true。但是,即使使用状态的新值触发useffect钩子,它也不会反映在setInterval函数中 代码沙箱: let间隔; 常量组件=()=>{ React.useffect(()=>{ console.log('状态更新为',状态); }); const[state,setState]=React.useState(false); const on=()=>{ 设置状态(真); 间隔=设置间隔(()=>{ console.log(状
setInterval
函数之前,我已将状态设置为true。但是,即使使用状态的新值触发useffect
钩子,它也不会反映在setInterval
函数中
代码沙箱:
let间隔;
常量组件=()=>{
React.useffect(()=>{
console.log('状态更新为',状态);
});
const[state,setState]=React.useState(false);
const on=()=>{
设置状态(真);
间隔=设置间隔(()=>{
console.log(状态);
}, 1000);
}
常数off=()=>{
设置状态(假);
间隔时间;
}
常量切换=()=>状态?关闭():打开()
返回(
切换状态
);
}
ReactDOM.render(
,
document.getElementById('容器')
);
它不应该在更新后使用更新的state值吗?如果您想在状态更改时重新加载组件,您应该像这样创建useEffect
React.useEffect(() => {
console.log('State updated to', state);
}, [state]);
您创建组件的方式与componentDidMount()
相同,第二个参数是数组,它与componentdiddupdate()
的依赖项类似。因此,只要状态发生更改,组件就会重新渲染
要解决setTimeout的无限调用,可以在创建函数的地方执行此操作
React.useCallback(() => {
setInterval(() => {
console.log(state);
}, 1000);
})
有了这个React,您就会知道您只想创建这个函数一次。我不是ReactJS专家,但我想您正在记录的
状态没有刷新,因为它声明了一次,而且从未刷新过。如果React.useState(false)
是提供状态的方法,则应在区间函数中使用它
下面是我试图解释的一个例子:
const object={value:false}
const notrefresh=object.value//我们在这里复制值
常量间隔=设置间隔(()=>{
const refreshed=object.value//这里我们使用引用来复制最新的值
日志(“刷新”,刷新)
log(“notrefresh”,notrefresh)
}, 500)
setTimeout(()=>object.value=true,1600)
setTimeout(()=>clearInterval(interval),2600)
传递给useEffect的函数中的值在每次渲染时都会刷新,因为useEffect使用传递给它的函数的新定义
但是传递给setInterval的函数只定义了一次,它会在旧的state值上关闭。尚未更新
使用钩子进行闭包是很棘手的,但要认识到的是,useEffect会为每个渲染创建一个新函数,因此每次函数在新状态值上关闭时都会创建一个新函数
然后,诀窍是在useEffect本身中调用与setInterval相关的代码,这本身取决于状态值的变化
React.useEffect(() => {
if(state) {
interval = setInterval(() => {
console.log(state);
}, 1000);
} else {
clearInterval(interval);
}
}, [state]);
或者,更好的方法是使用useInterval钩子为您处理这些细节。setInterval
始终可以访问组件的第一次渲染的值,因为传递给setInterval
的函数将围绕该值关闭,并且永远不会重新声明。您可以使用自定义挂钩修复此问题:
函数useInterval(回调、延迟){
const savedCallback=useRef();
useffect(()=>{
savedCallback.current=回调;
});
useffect(()=>{
函数tick(){
savedCallback.current();
}
让id=设置间隔(滴答声,延迟);
return()=>clearInterval(id);
},[延迟];
}
React贡献者之一Dan Abramov提供了React钩子和setInterval之间不匹配的实现和彻底解释。如果我们使用局部变量,那么即使变量不在函数范围内,它也会使用变量的更新值。钩住状态的闭包与变量的闭包有何不同?闭包意味着在函数范围之外的值上闭包。这种差异不是因为范围。这是因为一旦函数关闭某个值,它总是引用该变量。这就是setInterval回调发生的情况。它被定义了一次,并依附于状态的任何值。但是传递给useEffect的函数在每次渲染时都会被丢弃,并创建一个新的函数,然后关闭变量中的最新值。接受这个答案是因为它显示了解决此问题的简单方法。我所说的变量是假设我们有一个单独的全局声明的计数器变量,如果我们使用setInterval来增加它,那么它会增加它,而不需要在useffect钩子下定义它,但这是全局的。并在模块退出或程序退出之前一直在作用域中<代码>状态
在您的情况下,在渲染功能运行完成后,请退出范围。只有在该函数中定义的函数才能通过闭包访问该变量。这很有意义!我没想到会这样!我对这个问题有了一些“结论!”:)投票支持丹的文章!但是它并没有解释为什么会发生这种情况,而是提供了一个很好的解决方法。传递给setInterval
的函数在调用on
时只创建了一次,并且在创建时关闭了state
的值。Future呈现调用React.useState
并再次“查看”一个新的状态
,但当调用on
时创建的函数基本上停留在过去:它在创建时关闭了状态
,并且永远不会获得状态
的新值。因此,如果您查看Abramov的useInterval
,它在每次渲染时调用useffect
,并使用新版本的回调更新ref的.current
,该回调在该渲染调用的state
值上关闭。传递给本机setInterval
的函数从未更改,但该函数所做的只是调用另一个函数,该函数的引用实际上在每次重新调用时都在更新
React.useEffect(() => {
if(state) {
interval = setInterval(() => {
console.log(state);
}, 1000);
} else {
clearInterval(interval);
}
}, [state]);