从承诺返回响应后,获得局部状态变量的过时价值
我有一个带有两个按钮的React应用程序,该按钮在单击服务器上单击加载用户名。如果我一次单击一个按钮,并且等待响应,则行为有效,但是,如果我单击两者,则API的第二个按钮的响应将其写入值对状态的值,该状态是陈旧的,因此第一个按钮被卡在加载状态下。当Promise解决时,如何解决这个问题始终拥有最新数据?
import "./styles.css";
import LoadingButton from "@mui/lab/LoadingButton";
import { useRef, useState } from "react";
import { Typography } from "@mui/material";
const getUsersApi = (id) => {
const users = { "12": "John", "47": "Paul", "55": "Alice" };
return new Promise((resolve) => {
setTimeout((_) => {
resolve(users[id]);
}, 1000);
});
};
export default function App() {
const [users, setUsers] = useState({});
const availableUserIds = [12, 47];
const loadUser = (userId) => {
// Mark button as loading
const updatedUsers = { ...users };
updatedUsers[userId] = {
id: userId,
name: undefined,
isLoading: true,
isFailed: false
};
setUsers(updatedUsers);
// Call API
getUsersApi(userId).then((userName) => {
// Update state with user name
const updatedUsers = { ...users };
updatedUsers[userId] = {
...updatedUsers[userId],
name: userName,
isLoading: false,
isFailed: false
};
setUsers(updatedUsers);
});
};
return (
<div className="App">
{availableUserIds.map((userId) =>
users[userId]?.name ? (
<Typography variant="h3">{users[userId].name}</Typography>
) : (
<LoadingButton
key={userId}
loading={users[userId]?.isLoading}
variant="outlined"
onClick={() => loadUser(userId)}
>
Load User {userId}
</LoadingButton>
)
)}
</div>
);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
问题在于,Usestate的设置器是异步的,因此,在加载程序函数中,当您定义
const undedusers = {... users};
时,没有必要更新用户。幸运的是,Usestate的设定器提供了使我们能够访问以前的状态。
If you refactor your code like this, it should work:
Here a React playground with a simplified working version.
The problem is that useState's setter is asynchronous, so, in your loader function, when you define
const updatedUsers = { ...users };
, user is not necessary updated.Luckily, useState's setter provides allows us to access to the previous state.
If you refactor your code like this, it should work:
Here a React playground with a simplified working version.