首页 > 解决方案 > 使用 React useEffect、useState 和 setInterval 将秒数添加到 Intl.dateTimeFormat

问题描述

我遇到了一个奇怪的问题,在 setState() 钩子函数中更改克隆的顺序会改变预期的行为。

我试图每秒增加一秒的值。然而,这样做会直接导致秒数增加 2 而不是 1。

这有效

const [value, setValue] = useState(new Date());

useEffect(() => {
  const interval = setInterval(
  () =>
    setValue((value) => {
      const clonedDate = new Date(value.getTime());
      clonedDate.setSeconds(clonedDate.getSeconds() + 1); // Add one second to the time
      return clonedDate;
    }),
  1000
  );
  return () => {
    clearInterval(interval);
  };
}, []);

这增加了两秒而不是一秒

const [value, setValue] = useState(new Date());

useEffect(() => {
  const interval = setInterval(
  () =>
    setValue((value) => {
      value.setSeconds(value.getSeconds() + 1);
      const clonedDate = new Date(value.getTime());
      return clonedDate;
    }),
  1000
  );
  return () => {
    clearInterval(interval);
  };
}, []);

标签: reactjsdatesettimeout

解决方案


我唯一清楚的是,在第二个版本中,状态突变显然正在发生,但老实说,我不清楚确切的位置。似乎即使您正在创建一个的javascriptDate对象,它仍然在引用前一个数据对象的属性。

考虑以下表现出相同行为的示例:

function App() {
  const [value1, setValue1] = useState({ c: 0 });
  const [value2, setValue2] = useState({ c: 0 });

  useEffect(() => {
    const interval = setInterval(
      () =>
        setValue1((value) => {
          const clonedValue = { ...value };  // shallow copy first
          clonedValue.c = clonedValue.c + 1; // update copy
          return clonedValue;                // return copy
        }),
      1000
    );
    return () => {
      clearInterval(interval);
    };
  }, []);
  
  useEffect(() => {
    const interval = setInterval(
      () =>
        setValue2((value) => {
          value.c = value.c + 1;            // mutate current
          const clonedValue = { ...value }; // shallow copy
          return clonedValue;               // return copy
        }),
      1000
    );
    return () => {
      clearInterval(interval);
    };
  }, []);

  return (
    <div className="App">
      <h1>Non-mutaiton Version</h1>
      {value1.c}

      <h1>Mutation Version</h1>
      {value2.c}
    </div>
  );
}

编辑 add-seconds-to-intl-datetimeformat-with-react-useeffect-usestate-and-setint

不过有趣的是,如果您React.StrictMode从两者中删除 ,App则两者的性能相同。

StrictMode 目前有助于:

  • 识别具有不安全生命周期的组件
  • 关于旧版字符串引用 API 使用的警告
  • 关于不推荐使用 findDOMNode 的警告
  • 检测意外的副作用
  • 检测遗留上下文 API

检测意外的副作用

严格模式不能自动为您检测副作用,但它可以通过使它们更具确定性来帮助您发现它们。这是通过有意双重调用以下函数来完成的:

  • 类组件constructor,rendershouldComponentUpdate方法
  • 类组件静态getDerivedStateFromProps方法
  • 功能组件体
  • 状态更新函数(setState 的第一个参数)
  • 传递给useStateuseMemo或的函数useReducer

使用在 StrictMode 和非 StrictMode 下运行的原始日期对象进行演示:

编辑adding-seconds-to-intl-datetimeformat-with-react-useeffect-usestate-and-setint(分叉)


推荐阅读