1

考虑这个使用函数更新useState对象的简单示例:

App.tsx

import { useState } from 'react';

export default function App() {

  const [state, setState] = useState({
    id: 0,
  });

  const update = () => {

    setState(prev => {
      const id = Date.now();
      console.log('previous id:', prev.id, 'new id:', id);
      return {
        id,
      };
    });

  };

  return (
    <div>
      <div>state: {JSON.stringify(state)}</div>
      <button onClick={update}>Update</button>
    </div>
  );
}

将其放入标准的 create-react-app 打字稿模板(使用 React 17.0.2),并在开发模式下运行应用程序。继续单击更新按钮并观察控制台。很快就会遇到预期状态和实际状态之间的差异,例如

previous id:  1636301326090  new id:  1636301326260
previous id:  1636301326260  new id:  1636301326440
previous id:  1636301326440  new id: *1636301326611*
previous id: *1636301326612* new id:  1636301326804  // What???
previous id:  1636301326804  new id:  1636301326997

在上面的控制台日志中,id: 1636301326612状态突然出现,因为设置的状态是id: 1636301326611.

更奇怪的是,当应用程序是为生产而构建时,我无法重现这一点。此外,如果我放弃功能更新并仅将对象传递给setState注释掉的代码(由于原子性要求,在我的实际非玩具代码中不可行),问题似乎也不存在。

我完全不知所措。我是否以setState某种方式使用错误?

如有必要,我可以提供一个完整的示例 repo。

4

1 回答 1

2

这可能是因为在开发中,setState 在严格模式下被调用了两次。
设置状态值不取决于先前的值,而是取决于时间。这是一个副作用。

相关链接
https://reactjs.org/docs/strict-mode.html#detecting-unexpected-side-effects https://github.com/facebook/react/issues/12856

于 2021-11-09T13:10:17.700 回答