我有以下 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 -> 即使在第一次按下时结果也应该重复
结果 -> 不是那样的。这就是为什么我真的很困惑。
因此结果应该是一个不正确的列表,其中新用户重复。
按住按钮就会发生这种情况。但当您第一次按下按钮时,它不会发生。 为什么?
此操作根据先前渲染期间捕获的
users
的当前版本更新状态:
setUsers([newUser, ...users]);
然后调用 AJAX 操作,该操作有一个更新状态的回调。该回调还
根据先前渲染期间捕获的users
的当前版本更新状态,因为调用时
状态未更新:
setUsers([res.data, ...users]);
在两种
情况下,users
具有相同的值。因此,
两个操作都将状态更新为单个“测试”用户以及现有
users
的相同列表。因此,这两个操作的结果都是一个新状态,只有一个“测试”用户前置。为了实现您期望的行为,您可以修改状态更新以使用当前版本的状态在批处理中,而不是从先前渲染中捕获的状态版本。例如:
setUsers(prev => [res.data, ...prev]);