提问人:ramcrys 提问时间:10/31/2023 最后编辑:ramcrys 更新时间:10/31/2023 访问量:43
在存在异步代码的情况下进行多状态更新 (useState)
React multiple state updates (useState) in the presence of async code
问:
我有以下 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 次重新渲染。
第一个将呈现新列表,并在开头附加 id = 0 的新测试用户。Users
然后,在 promise 解析后,第二个将再次呈现最新列表,并在开头附加 id = 11 的(从服务器返回)测试用户。我知道 React 的更新批处理,但这些显然应该是 2 个“批处理”,因此是 2 个重新渲染,对吧?Users
因此,结果应该是与新用户重复的错误列表。
但是,我测试了此代码,它仅使用一个新用户正确呈现列表。我在这里理解错了什么?提前致谢。
编辑:当然,我不是在谈论多次按下按钮。我们应该只讨论只按一次按钮。
IMO -> 即使在第一次按下时,结果也应该重复
结果 -> 不是那样的。这就是为什么我真的很困惑。
答:
因此,结果应该是与新用户重复的错误列表。
继续按下按钮,就会发生这种情况。但它不会在你第一次按下按钮时发生。
为什么?
此操作根据上一次渲染期间捕获的当前版本更新状态:users
setUsers([newUser, ...users]);
然后调用 AJAX 操作,该操作具有更新状态的回调。该回调还会根据上一次渲染期间捕获的当前版本更新状态,因为调用时状态未更新:users
setUsers([res.data, ...users]);
在这两种情况下,具有相同的值。因此,这两个操作都更新了单个“测试”用户以及现有 .因此,这两个操作的结果都是一个新状态,其中只有一个“测试”用户。(这仍然会导致两次重新渲染。它们只是呈现相同的视觉信息,并且快速连续,因此您不会观察到不同的 ID。users
users
若要实现预期行为,可以修改状态更新,以在批处理中使用当前版本的状态,而不是从上一次渲染中捕获的状态版本。例如:
setUsers(prev => [res.data, ...prev]);
评论
users
评论