在存在异步代码的情况下响应多个状态更新(useState)

问题描述 投票:0回答:1

我有以下 React 18(带有 TypeScript)代码:

interface User {
  id: number;
  name: string;
}

function App() {
  const [users, setUsers] = useState<User[]>([]);
  const [error, setError] = useState("");

  useEffect(() => {
    axios
      .get<User[]>("https://jsonplaceholder.typicode.com/users")
      .then((res) => setUsers(res.data));
  }, []);

  const addUser = () => {
    const newUser = { id: 0, name: "Test" };
    setUsers([newUser, ...users]);
    axios
      .post("https://jsonplaceholder.typicode.com/users", newUser)
      .then((res) => {
        console.log("size", users.length);
        setUsers([res.data, ...users]);
      })
      .catch((err) => setError(err.message));
  };

  return (
    <>
      {error && <p>{error}</p>}
      <button onClick={addUser}>Add</button>
      <ul>
        {users.map((user) => (
          <li key={user.id}>{user.name}</li>
        ))}
      </ul>
    </>
  );
}

export default App;

据我了解,我们将在这里进行 2 次重新渲染。 第一个将渲染新的

Users
列表,并在开头附加 id = 0 的新测试用户。

然后,在承诺解决后,第二个将再次呈现最新的

Users
列表,并在开头附加(从服务器返回的)测试用户,id = 11。我知道 React 的更新批处理,但这些显然应该是 2 个“批次”,因此 2 次重新渲染,对吗?

因此结果应该是一个不正确的列表,其中新用户重复。

但是,我测试了这段代码,它仅正确地呈现了 one 新用户的列表。我在这里理解不正确是什么?预先感谢。

编辑:当然我不是在谈论多次按下按钮。我们应该讨论只按一次按钮。

IMO -> 即使在第一次按下时结果也应该重复

结果 -> 不是那样的。这就是为什么我真的很困惑。

javascript reactjs asynchronous react-hooks
1个回答
1
投票

因此结果应该是一个不正确的列表,其中新用户重复。

按住按钮就会发生这种情况。但当您第一次按下按钮时,它不会发生。 为什么?

此操作根据先前渲染期间捕获的

users

的当前版本更新状态:

setUsers([newUser, ...users]);

然后调用 AJAX 操作,该操作有一个更新状态的回调。该回调

根据先前渲染期间捕获的users的当前版本更新状态,因为调用时

状态未更新
setUsers([res.data, ...users]);

两种

情况下,users具有相同的值。因此,

两个
操作都将状态更新为单个“测试”用户以及现有users的相同列表。因此,这两个操作的结果都是一个新状态,只有一个“测试”用户前置。
为了实现您期望的行为,您可以修改状态更新以使用当前版本的状态

在批处理

中,而不是从先前渲染中捕获的状态版本。例如: setUsers(prev => [res.data, ...prev]);

© www.soinside.com 2019 - 2024. All rights reserved.