首页 > 解决方案 > 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>
  )
}

的初始值为myparam1,因此loop函数开始递归。

然后,父组件在 3 秒后更新道具,并且在子组件的钩子中正确检测到它,useEffect()但是循环函数没有检测到道具更改并继续递归运行。

从我的角度来看,预期的行为是递归loop()函数(myparamloop()

    if(props.myparam) {                // DOES NOT DETECT PROP CHANGE PROPERLY!!!
      setTimeout(() => loop(), 1000)
    }

这种奇怪的行为有什么解释吗?

提前致谢!

标签: javascriptreactjsreact-hooks

解决方案


我在回答自己,因为我相信我找到了答案。

而不是props.myparam在函数中用作条件loop()

    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])

然后在useEffect()ChildComponent我添加一个清理函数以设置runLoop为 false - 脚本按预期工作。

所以我的结论是 React 基本上在每次渲染时都会实例化组件,并且之前渲染中的变量不会被更新(除非它们在清理时显式更新)。


推荐阅读