问题描述
我正在尝试在for循环中更新setState,但是由于某种原因,状态没有被复制,只是被替换了。应该有2个客户,而不是我得到一个。谁能告诉我为什么会这样吗? console.log返回两个客户端。
const handleViewClients = () => {
for (let i = 0; i < clients.length; i++) {
console.log(clients[i].clientid);
fetch("http://localhost:3005/all-clients/" + clients[i].clientid)
.then((response) => response.json())
.then((result) => {
console.log(result);
setBarbersClient({
...barbersClient,client: result,});
});
}
};
我也尝试过... console.log返回我需要的内容
Promise.all(
clients.map((client) =>
fetch("http://localhost:3005/all-clients/" + client.clientid)
)
)
.then((resp) => resp.json())
.then((result) => {
console.log(result.username)
setBarbersClient({
...barbersClient,});
});
这是来自服务器端的路由
app.get("/all-clients/:clientid",(req,res) => {
db.NewClientsx.findOne({
where: {
id: req.params.clientid,},}).then((response) => {
res.json(response);
});
});
解决方法
这里没有介绍同步代码与异步代码的一些基本概念。状态更改(和获取)是异步的,因此直到 执行完此同步循环后,它才会运行(在此期间状态值将保持不变)。同样,出于这个原因和其他原因,以循环方式更改状态也是一个坏主意。
获取所有客户端,然后最后对 all 所获取的数据进行一个状态更改。您可以利用Promise.all
和Promise.spread
之类的工具来实现此目的。这是一个进行多次提取然后分批处理结果的示例:How can I fetch an array of URLs with Promise.all?
您犯了两个明显的错误,其中任何一个足以引起您所看到的行为。
1。您正在覆盖client
属性。
每次调用setter函数时,都会覆盖client
属性的先前值。您将需要一些支持多个值的数据结构,例如地图:
setBarbersClient({
...barbersClient,clients: {
...barbersClient.clients,[result.id]: result
},});
您将需要稍微更改渲染逻辑以适应新的数据结构。
2。您正在使用陈旧的引用。
当您访问barbersClient
时,它的设置器可能已经被调用了一个不同的值,并且您对它的引用仍然引用了上次运行渲染函数的值。您可以使用set状态操作回调来确保您的引用是最新的。
setBarbersClient(previousValue => {
...previousValue,clients: {
...previousValue.clients,});
previousValue
在设置状态操作函数体内永远不会陈旧。