反应状态没有在 SetInterval 方法中正确更新

Posted

技术标签:

【中文标题】反应状态没有在 SetInterval 方法中正确更新【英文标题】:React State not getting updated properly in SetInterval Methods 【发布时间】:2021-04-29 23:18:32 【问题描述】:

我在 UI 和 OnClick 事件处理程序中有一个按钮,我必须运行一个设置间隔计时器。在设置间隔计时器中,我正在检查条件,如果满足条件,我正在更新状态,但它不能正常工作。

import React,  useState, useEffect, useRef  from "react";
import ReactDOM from "react-dom";

function Counter() 
  let [count, setCount] = useState(0);
  let [gg, setgg] = useState(false);

  function countdownTimer() 
    console.log(count + gg.toString());
    if (count > 10) 
      setgg(true);
    
    setCount((count) => count + 1);
  

  function handleClick() 
    let id = setInterval(countdownTimer, 1000);
  

  return (
    <div>
      <button onClick=handleClick>Click</button>
      <h1>count + gg.toString()</h1>
    </div>
  );


const rootElement = document.getElementById("root");

// Second interval to demonstrate the issue.
// Fast updates from it cause the Counter's
// interval to constantly reset and never fire.
setInterval(() => 
  ReactDOM.render(<Counter />, rootElement);
, 1

00);

在 countdownTimer 函数中有一个 console.log,它总是打印“0 false”,但 UI 中的组件正在更新为正确的数字。

请告诉我为什么

    console.log 中的计数始终为“0” 如果计数始终为零,如何正确更新状态? 如何在 countdowntimer 函数的 console.log() 中打印正确的计数值。

代码沙盒链接:https://codesandbox.io/s/dank-grass-7o4ms?file=/src/index.js

组件更新正确但console.log始终为零的屏幕截图。

【问题讨论】:

【参考方案1】:

问题

    console.log 中的计数始终为“0”

陈旧的count 状态包含在updfun 回调中。

    如果计数始终为零,如何正确更新状态?

您使用了功能状态更新,因此每次更新都正确地从前一个状态更新,不是回调入队时的状态。

    如何在 countdowntimer 函数的 console.log() 中打印正确的计数值。

使用useEffect 在更新时发出日志记录状态的副作用,并检查count 是否大于10 以设置gg 状态。

function Counter() 
  const [count, setCount] = useState(0);
  const [count, setCount] = useState(0);
  const [gg, setgg] = useState(false);

  useEffect(() => 
    console.log(count + gg.toString());
    if (count > 10) 
      setgg(true);
    
  , [count, gg]);

  useEffect(() => () => clearInterval(timerRef.current), []);

  function updfun() 
    setCount((count) => count + 1);
  

  function handleClick() 
    timerRef.current = setInterval(updfun, 1000);
  

  return (
    <div>
      <button onClick=handleClick>Click</button>
      <h1>count + gg.toString()</h1>
    </div>
  );

【讨论】:

陈旧状态是什么意思?你能解释一下吗? @Ravi 啊,我一直认为“陈旧状态”这个词是不言自明的。基本上count 的值在渲染周期中被关闭(参见Closures),回调被保存在setInterval 中。可以将其视为创建间隔并一遍又一遍地调用时的状态的“快照”。【参考方案2】:

您需要先设置 count 值,然后将其更新为状态,以便您的 countdounTimer 应该像

 function countdownTimer() 
    console.log(count + gg.toString());
    if (count > 10) 
      setgg(true);
    
    setCount(++count);
  

 function countdownTimer() 
    console.log(count + gg.toString());
    if (count > 10) 
      setgg(true);
    
    count=count+1
    setCount(count);
  

Click Here 用于演示

【讨论】:

这只“有效”,因为你正在改变(++countcount += 1)状态对象,这在 React 中是一个非常糟糕的习惯。 Using State Correctly

以上是关于反应状态没有在 SetInterval 方法中正确更新的主要内容,如果未能解决你的问题,请参考以下文章

不能在反应中使用 setinterval() 附加数组(状态元素)

反应钩子:新状态值未反映在 setInterval 回调中

如何在反应中使用 setInterval?

如何正确更新反应钩子状态中的数组

修改状态和更新减速器的正确方法? (反应/还原)

如何在 React 功能组件中正确设置 setInterval 计时器?