更新的状态值不会在反应中的函数内部更新

Posted

技术标签:

【中文标题】更新的状态值不会在反应中的函数内部更新【英文标题】:updated state value are not updated inside function in react 【发布时间】:2021-10-06 12:06:15 【问题描述】:

react state 更新的值显示在 use Effect 但内部函数只显示一个旧值。

const [counter, setCounter] = useState(0);

我正在尝试更新设置间隔函数内的计数器值

 const handleIncrease = () => 
clearInterval(intervalval);
if (counter < 10) 
  let increment = setInterval(() => 
    console.log("isCounterContinue@handleIncrease", counter);
    setCounter((prev) => prev + 1);
  , 1000);
  setIntervalval(increment);

; 显示内部 useEffect 更新的值。但内部函数handleIncrease 只显示旧值 基本上,我正在尝试做计数器值超过 30 时不会增加。

代码链接:https://codesandbox.io/s/bold-cdn-zzbs2?file=/src/App.js

【问题讨论】:

这能回答你的问题吗? State not updating when using React state hook within setInterval 您的代码箱中的代码似乎可以按照您描述的方式运行...但它也与您在此处共享的 sn-p 不匹配。有什么问题? handleIncrease 函数内的计数器值未更新。因此,如果我尝试添加条件(基于计数器状态),则不会在 handleIncrease 函数中应用 handleIncrease 仅在单击按钮时调用,具有当前状态。点击处理程序中有什么要更新的?我认为您真正追求的是在间隔的回调中访问更新的counter 状态,该状态每秒“滴答”一次。 在更新计数器状态后每 1000 毫秒在点击处理程序中。但它没有在 handleIncrease 函数中显示更新的值。我很困惑里面 useEffect 更新的值被显示,但里面的 handleIncrease 计数器值没有显示 【参考方案1】:

handleIncrease 仅在单击按钮时调用,具有当前状态。在点击处理程序中没有什么要更新的。我认为您真正想要的是访问间隔回调中更新的counter 状态,该回调每秒“滴答”一次。或者更准确地说,响应 isCounterContinue 状态切换 false 以在达到限制时停止间隔。

使用 ref 来保存对间隔计时器的引用,并使用它来设置/清除,而不是在外壳中过时的状态。

const Timer = () => 
  const [counter, setCounter] = useState(0);
  const intervalRef = useRef();

  useEffect(() => 
    console.log( counter );
    if (counter >= 5) 
      clearInterval(intervalRef.current);
    
  , [counter]);

  const handleIncrease = () => 
    clearInterval(intervalRef.current);
    intervalRef.current = setInterval(() => 
      setCounter((prev) => prev + 1);
    , 1000);
  ;

  const handleDecrease = () => 
    clearInterval(intervalRef.current);
    intervalRef.current = setInterval(() => 
      setCounter((prev) => prev - 1);
    , 1000);
  ;

  const handleStop = () => 
    clearInterval(intervalRef.current);
  ;

  return (
    <>
      <div>counter</div>
      <div>
        <button onClick=handleDecrease>Decrease</button>
        <button onClick=handleStop>Stop</button>
        <button onClick=handleIncrease>Increase</button>
      </div>
    </>
  );
;

建议

递增/递减处理程序除了添加到计数之外基本相同。使用 curried 函数通过关闭递增值来处理这两种情况。由于“停止”处理程序共享逻辑来清除间隔,因此使用 0 是一个虚假值这一事实,并且只为真实(即非零)数值重新启动间隔计时器,并对所有三个按钮使用一个处理程序。

const handleIncrease = (val) => () => 
  clearInterval(intervalRef.current);
  if (val) 
    intervalRef.current = setInterval(() => 
      setCounter((prev) => prev + val);
    , 1000);
  
;

...

<button onClick=handleIncrease(-1)>Decrease</button>
<button onClick=handleIncrease(0)>Stop</button>
<button onClick=handleIncrease(1)>Increase</button>

【讨论】:

它正在工作,你能解释一下为什么没有 Ref,handleIncrease 函数中不显示更新值的原因。 @ShatishDesai 仅在单击时显示当前的counter 值,而不是在间隔“滴答”时显示。如果您继续每秒单击“增加”按钮,您将看到更新的counter 状态。如果您等待几秒钟并然后再次单击“增加”,您将看到当前的counter 状态。

以上是关于更新的状态值不会在反应中的函数内部更新的主要内容,如果未能解决你的问题,请参考以下文章

反应无状态子组件不会更新父组件中的状态更改

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

React - 每当更新反应上下文中的状态时如何调用函数?

使用React useContext hook进行分派调用后,反应状态不会更新

数组状态更新后反应不重新渲染

功能性反应如何不重置状态?