Reactjs 如何处理useEffect闭包中的过时状态值?

Reactjs 如何处理useEffect闭包中的过时状态值?,reactjs,react-hooks,Reactjs,React Hooks,下面的示例是一个计时器组件,它有一个按钮(用于启动计时器)和两个标记,显示经过的秒数和经过的秒数乘以2 但是,它不起作用( 代码 import React, { useState, useEffect } from "react"; const Timer = () => { const [doubleSeconds, setDoubleSeconds] = useState(0); const [seconds, setSeconds] = useState

下面的示例是一个计时器组件,它有一个按钮(用于启动计时器)和两个标记,显示经过的秒数和经过的秒数乘以2

但是,它不起作用(

代码

import React, { useState, useEffect } from "react";

const Timer = () => {
  const [doubleSeconds, setDoubleSeconds] = useState(0);
  const [seconds, setSeconds] = useState(0);
  const [isActive, setIsActive] = useState(false);

  useEffect(() => {
    let interval = null;
    if (isActive) {
      interval = setInterval(() => {
        console.log("Creating Interval");
        setSeconds((prev) => prev + 1);
        setDoubleSeconds(seconds * 2);
      }, 1000);
    } else {
      clearInterval(interval);
    }
    return () => {
      console.log("Destroying Interval");
      clearInterval(interval);
    };
  }, [isActive]);

  return (
    <div className="app">
      <button onClick={() => setIsActive((prev) => !prev)} type="button">
        {isActive ? "Pause Timer" : "Play Timer"}
      </button>
      <h3>Seconds: {seconds}</h3>
      <h3>Seconds x2: {doubleSeconds}</h3>
    </div>
  );
};

export { Timer as default };
过时值的问题仍然存在()

问题

那么,对于这个场景的建议是什么呢?我是否接受性能影响并简单地将“秒”添加到依赖项数组中?我是否创建另一个依赖于“秒”的useEffect块并在其中调用“setDoubleSeconds()”?我是否将“秒”和“doubleSeconds”合并到单个状态对象中?我是否使用引用

此外,您可能会想,“为什么不简单地将
Seconds x2:{doubleSeconds}
”更改为
Seconds x2:{Seconds*2}
,并删除“doubleSeconds”状态?“。在我的实际应用程序中,doubleSeconds被传递给子组件,我不希望子组件知道秒如何映射到doubleSeconds,因为这会降低子组件的可重用性

谢谢

  • 我是否接受了性能上的打击,并简单地向依赖项数组添加“秒”
  • 我是否创建另一个依赖于“秒”的useEffect块并在其中调用“setDoubleSeconds()”
  • 我是否将“秒”和“双秒”合并到单个状态对象中
  • 我使用refs吗
尽管我个人更愿意选择第二种方法,但它们都能正常工作:

useffect(()=>{
设置双秒(秒*2);
},[秒];
然而:

在我的实际应用程序中,doubleSeconds被传递给子组件,我不希望子组件知道如何将seconds映射到doubleSeconds,因为这会降低子组件的可重用性

这是有问题的。子组件的实现方式可能如下所示:

constchild=({second})=>(
秒:{second}s

);
和父组件应如下所示:

const[seconds,setSeconds]=useState(0);
useffect(()=>{
//换秒
}, []);
返回(
);
这将是一种更加清晰和简洁的方式

  • 我是否接受了性能上的打击,并简单地向依赖项数组添加“秒”
  • 我是否创建另一个依赖于“秒”的useEffect块并在其中调用“setDoubleSeconds()”
  • 我是否将“秒”和“双秒”合并到单个状态对象中
  • 我使用refs吗
尽管我个人更愿意选择第二种方法,但它们都能正常工作:

useffect(()=>{
设置双秒(秒*2);
},[秒];
然而:

在我的实际应用程序中,doubleSeconds被传递给子组件,我不希望子组件知道如何将seconds映射到doubleSeconds,因为这会降低子组件的可重用性

这是有问题的。子组件的实现方式可能如下所示:

constchild=({second})=>(
秒:{second}s

);
和父组件应如下所示:

const[seconds,setSeconds]=useState(0);
useffect(()=>{
//换秒
}, []);
返回(
);

这将是一种更加清晰和简洁的方法。

您可以通过几种方式访问effect回调中的值,而无需将其添加为dep

  • 设置状态
    。您可以通过状态变量的设置器点击状态变量的最新值
  • Ref。你可以将Ref作为依赖项传递,它永远不会更改。不过,你需要手动使其保持最新
  • 然后,您可以使用
    secondsRef.current
    访问代码块中的
    seconds
    ,而无需触发deps更改

    setDoubleSeconds(secondsRef.current * 2);
    
    在我看来,您永远不应该从deps数组中忽略依赖项。如果您需要deps不更改,请使用如上所述的方法确保您的值是最新的

    总是首先考虑是否有更优雅的方式编写代码,而不是将值放入回调中。在示例中,代码> DouBuffEnss/Cuth>可以表示为<代码>秒< /代码>。< /P>

    const [seconds, setSeconds] = useState(0);
    const doubleSeconds = seconds * 2;
    

    有时应用程序并不是那么简单,所以您可能需要使用上面描述的hack。

    您可以通过几种方式访问effect回调中的值,而无需将其添加为dep

  • 设置状态
    。您可以通过状态变量的设置器点击状态变量的最新值
  • Ref。你可以将Ref作为依赖项传递,它永远不会更改。不过,你需要手动使其保持最新
  • 然后,您可以使用
    secondsRef.current
    访问代码块中的
    seconds
    ,而无需触发deps更改

    setDoubleSeconds(secondsRef.current * 2);
    
    在我看来,您永远不应该从deps数组中忽略依赖项。如果您需要deps不更改,请使用如上所述的方法确保您的值是最新的

    总是首先考虑是否有更优雅的方式编写代码,而不是将值放入回调中。在示例中,代码> DouBuffEnss/Cuth>可以表示为<代码>秒< /代码>。< /P>

    const [seconds, setSeconds] = useState(0);
    const doubleSeconds = seconds * 2;
    
    有时应用程序并不是那么简单,所以您可能需要使用上面描述的hack

    const [seconds, setSeconds] = useState(0);
    const doubleSeconds = seconds * 2;