Spread Operator不复制React中的结果 1您正在覆盖client属性 2您正在使用陈旧的引用

问题描述

我正在尝试在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.allPromise.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在设置状态操作函数体内永远不会陈旧。