反应“间隔”始终处于相同状态

时间:2019-10-14 13:23:10

标签: reactjs typescript

我正在将React 16.10与打字稿一起使用。 我有以下代码:

  const [state, setState] = useState<State>({
        test: 1
    });  

    //On component mount we start our interval
    useEffect(() => {
        const timerID = setInterval(timer, 5000); //every 5 seconds

        return function cleanup() {
            //When we leave component we stop the timer
            clearInterval(timerID);
        };
    }, []); 

   function timer() {
        if(state.test === 3){
            //HE WILL NEVER ENTER THIS CODE FUNCTION
        }

        setState({...state, test: 3}); // Next time we should have the value 3, BUT IT HAS NEVER THIS VALUE?!?!
    }

   return (
        <>
     <span>The output is {state.test}</span> //First it is showing 1, after 5 seconds 3. Working great
        </>
    );

我将test的值更改为间隔“ timer”中的数字3。 setState工作正常。我可以在组件中看到该值,看到数字从1切换到3。

但是在计时器功能中,该值从未更改。每次默认值为1。

我做错了什么?

3 个答案:

答案 0 :(得分:1)

您需要向useEffect添加依赖项

 //On component mount we start our interval
  useEffect(() => {
      const timerID = setInterval(timer, 5000); //every 5 seconds

      return function cleanup() {
          //When we leave component we stop the timer
          clearInterval(timerID);
      };
  }, [state.test]); // <- here add dependency
  

原因

您的效果函数仅在组件安装并存储timer函数参考时被调用一次。现在,当您更改状态时,您的timer function也是updated outside,而不是inside of useEffect

useEffect仍在state was 1时使用旧参考,因此inside it State always going to be 1为此referred timer function

现在,当您通过state.test作为依赖项时。状态更改后,您的效果将更新,并且现在开始使用具有新状态的新timer function

现在,您可以在timer function中更新状态。并且您的状况可以正确评估。

如有任何疑问,请发表评论。

答案 1 :(得分:0)

您没有做错任何事情,您的useEffect()在内存中具有完全不同的值,并且不知道有关useEffect()的这种行为,您什么也没有告诉useEffect()停止关注旧值并开始查看新值。正如Hardik所写,您的useEffect()仅被调用一次,因此您仍然具有最初在其中调用的旧值,并且useEffect不知道您的计时器此后已更改。它将永远引用该原始值。

您可以做的是完全删除空数组作为第二个参数,您会注意到行为上的差异。

按照Hardik的建议,直接引用您在状态中使用的变量是可行的方法。

因此,useEffect()并没有被再次调用,结果,它里面的任何东西都没有再次运行,因此所有这些都已过时。

facebook团队提供的缓解此错误的提示之一:

  • 当您有一个引用状态,属性或上下文值的useEffect函数时,请将其添加到依赖项列表中。换句话说,如果您有一个名为 trackId 的道具,则需要执行以下操作:

     useEffect(() => {
       trackId
     }, [trackId]);
    

答案 2 :(得分:-1)

我看到了两个潜在的问题,首先您需要打电话给this.statethis.setState。我猜状态是不确定的,但是this.state不会。您也不需要在setState函数中扩展状态,this.setState({ test: 3});足够好,setState函数可以为您完成此任务。

第二步,您需要为每个更改更新状态,看起来您仅在测试值为3时才更新,对此实现感到惊讶的是3次。