React组件中的递归函数调用



我有一个关于以下(非常奇怪(问题的问题。

我有一个像这样的父组件:

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基本上在每次渲染时都会实例化组件,并且上一次渲染中的变量不会更新(除非它们在清理时明确更新(。