处理对象数组作为状态的问题

问题描述 投票:2回答:2

我正在尝试将状态设置为对象数组,但它失败了。

我使用CRA创建项目,并使用react-hooks进行状态。我使用react-apollo-hooks从graphql server获取数据。我刚刚在codesandbox中声明了数据对象,但它不会影响我的问题。

对于每次单击,使用data(对象数组)设置state(对象数组)。

const data = {
  lists: [
    {
      id: "1"
    },
    {
      id: "2"
     },
    {
      id: "3"
    }
   ]
};

const Sample = () => {
  const [sample, setSample] = useState([]);

  const Updator = async () => {
    try {
      await data.lists.map(list => {
        setSample([
          ...sample,
          {
            label: list.id,
            value: list.id
          }
        ]);
        return true;
      });
      console.log(sample);
    } catch (err) {
      throw err;
    }
  };
  return (
    <div>
      <React.Fragment>
        <button
          onClick={e => {
            Updator();
          }}
        >
          Click me
        </button>
        <p>
          <strong>
            {sample.map(single => {
              return <div>{single.label}</div>;
            })}
          </strong>
        </p>
      </React.Fragment>
    </div>
  );
};

我在下面附上了所有测试代码。

这是codesandbox链接。 https://codesandbox.io/s/zr50rv7qjp

我期待的结果

123

点击,但结果是

3

此外,对于额外的点击,预期的结果是

123
123

我明白了

3
3
.

当我使用setSample()时,我希望函数类似于Array.push()。但它忽略了所有以前的数据,期望最后一个。

任何帮助都会感激不尽!

reactjs react-hooks
2个回答
2
投票

state updater does batching,因为你在地图中调用setSample方法,所以只有你的最后一个值被写入状态。

这里最好的解决方案是从map返回数据,然后像下面一样更新状态。

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const data = {
  lists: [
    {
      id: "1"
    },
    {
      id: "2"
    },
    {
      id: "3"
    }
  ]
};

const Sample = () => {
  const [sample, setSample] = useState([]);

  const Updator = async () => {
    try {
      const newData = data.lists.map(list => {
        return {
          label: list.id,
          value: list.id
        };
      });
      setSample([...sample, ...newData]);
    } catch (err) {
      throw err;
    }
  };
  return (
    <div>
      <React.Fragment>
        <button
          onClick={e => {
            Updator();
          }}
        >
          Click me
        </button>
        <p>
          <strong>
            {sample.map((single, index) => {
              return <div key={index}>{single.label}</div>;
            })}
          </strong>
        </p>
      </React.Fragment>
    </div>
  );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<Sample />, rootElement);

Working Demo

另一种解决方案是使用回调方法更新状态,但必须避免多次调用状态更新。


1
投票

当你循环并调用sample时,你正在破坏setSample,它本身没有最新版本。这就是为什么它只在样本列表中放入3,因为地图的最后一次迭代将破坏一个空的样本列表并添加3。

为了确保您拥有最新的样本值,您应该将函数传递给setSample。此函数将从react获取最新版本的state var。

setSample((latest) => {
    return [
      ...latest,
      {
        label: list.id,
        value: list.id
      }
    ]
});
© www.soinside.com 2019 - 2024. All rights reserved.