【问题标题】:Problem on handling array of object as state将对象数组作为状态处理的问题
【发布时间】:2019-04-23 08:34:52
【问题描述】:

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

我使用 CRA 创建项目,并为状态使用 react-hooks。 我使用 react-apollo-hooks 从 graphql 服务器获取数据。 我只是在codesandbox中声明了数据对象,但这并不影响我的问题。

对于每次点击,使用数据(对象数组)设置状态(对象数组)。

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>
  );
};

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

这里是代码框链接。 https://codesandbox.io/s/zr50rv7qjp

我期待结果

123

通过点击,但结果是

3

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

123
123

我得到

3
3

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

任何帮助将不胜感激!

【问题讨论】:

    标签: reactjs react-hooks


    【解决方案1】:

    state updater does batching 并且由于您在 map 中调用 setSample 方法,因此只有您的最后一个值被写入状态。

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

    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

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

    【讨论】:

      【解决方案2】:

      当您循环调用setSample 时,您正在破坏sample,它不会拥有最新版本的自身。这就是为什么它只将 3 放在样本列表中的原因,因为映射的最后一次迭代将破坏一个空样本列表并添加 3。

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

      setSample((latest) => {
          return [
            ...latest,
            {
              label: list.id,
              value: list.id
            }
          ]
      });
      

      【讨论】:

        猜你喜欢
        • 2021-10-07
        • 1970-01-01
        • 2015-02-19
        • 1970-01-01
        • 1970-01-01
        • 2012-11-19
        • 1970-01-01
        • 2018-11-18
        • 2020-09-06
        相关资源
        最近更新 更多