我有一个关于以下(非常奇怪(问题的问题。
我有一个像这样的父组件:
function ParentComponent() {
const [myParam, setMyParam] = React.useState(1);
useEffect(() => {
setTimeout(() => {
console.log('Setting myParam to 0...');
setMyParam(0);
}, 3000);
}, []);
return (
<div>
<ChildComponent myparam={myParam}></ChildComponent>
</div>
)
}
从这个父组件,我将参数myParam
(默认值为1(作为道具传递给子组件。
子组件如下所示:
function ChildComponent(props) {
const loop = () => {
if(props.myparam) { // DOES NOT DETECT PROP CHANGE PROPERLY!!!
setTimeout(() => loop(), 1000)
}
}
React.useEffect(() => {
if(props.myparam) {
loop();
}
}, [props.myparam])
return (
<div>
Loop demo
</div>
)
}
myparam
的初始值为1,因此loop
函数开始其递归。
然后,父组件在3秒后更新prop,并且在子组件的useEffect()
钩子中正确检测到它,但循环函数没有检测到prop的更改,并保持递归运行。
从我的角度来看,预期的行为是递归函数(loop()
(应该在道具myparam
获得值0(从父组件更改(后停止执行,因为在loop()
函数中,我有这样的IF语句:
if(props.myparam) { // DOES NOT DETECT PROP CHANGE PROPERLY!!!
setTimeout(() => loop(), 1000)
}
对这种奇怪的行为有什么解释吗?
提前感谢!
我在回答自己,因为我相信我找到了答案。
代替在loop()
函数中使用props.myparam
作为条件:
if(props.myparam) { // DOES NOT DETECT PROP CHANGE PROPERLY!!!
setTimeout(() => loop(), 1000)
}
我使用一个局部变量作为标志:
if(runLoop) {
setTimeout(() => loop(), 1000)
}
在useEffect()
中,在ChildComponent
中,我有这个:
React.useEffect(() => {
if(props.myparam) {
runLoop = 1;
loop();
} else {
runLoop = 0;
}
return () => {
runLoop = 0; // this solves the issue
}
}, [props.myparam])
然后,在ChildComponent
中的useEffect()
中,我添加了一个清除函数,将runLoop
设置为false——脚本按预期工作。
因此,我的结论是,React基本上在每次渲染时都会实例化组件,并且上一次渲染中的变量不会更新(除非它们在清理时明确更新(。