我正在尝试将状态设置为对象数组,但它失败了。
我使用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()。但它忽略了所有以前的数据,期望最后一个。
任何帮助都会感激不尽!
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);
另一种解决方案是使用回调方法更新状态,但必须避免多次调用状态更新。
当你循环并调用sample
时,你正在破坏setSample
,它本身没有最新版本。这就是为什么它只在样本列表中放入3,因为地图的最后一次迭代将破坏一个空的样本列表并添加3。
为了确保您拥有最新的样本值,您应该将函数传递给setSample
。此函数将从react获取最新版本的state var。
setSample((latest) => {
return [
...latest,
{
label: list.id,
value: list.id
}
]
});