我试图将状态设置为对象数组,但是失败。
我使用CRA创建了项目,并对状态使用了响应挂钩。 我使用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>
);
};
我在下面附加了所有测试代码。
这里是codeandbox链接。 https://codesandbox.io/s/zr50rv7qjp
我希望得到的结果
123点击
,但结果是
3
此外,对于其他点击,预期结果是
123 123
我得到
3 3。
当我使用setSample()时,我期望的功能类似于Array.push()。但是它忽略了所有先前的数据以及最后一个数据。
任何帮助都会令人感激!
答案 0 :(得分:2)
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);
另一种解决方案是使用回调方法来更新状态,但必须避免多次调用状态更新。
答案 1 :(得分:1)
您正在破坏sample
,当您循环并调用setSample
时,它本身不会具有最新版本。这就是为什么它只将3放在样本列表中的原因,因为地图的最后一次迭代将破坏一个空的样本列表并添加3。
为确保您拥有最新的样本值,应将一个函数传递给setSample
。该功能将从react获取状态var的最新版本。
setSample((latest) => {
return [
...latest,
{
label: list.id,
value: list.id
}
]
});