将对象数组作为状态处理的问题
Problem on handling array of object as state
我试图将状态设置为对象数组,但失败了。
我使用 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>
);
};
我在下面附上了所有测试代码。
这里是codesandboxlink。
https://codesandbox.io/s/zr50rv7qjp
我期待
的结果
123
通过点击,但结果是
3
此外,对于额外的点击,预期结果是
123
123
然后我明白了
3
3
.
当我使用 setSample() 时,我希望函数类似于 Array.push()。但它忽略了除最后一个之外的所有先前数据。
如有帮助将不胜感激!
您正在破坏 sample
,当您循环和调用 setSample
时,它本身不会有最新版本。这就是为什么它只将 3 放入样本列表中的原因,因为地图的最后一次迭代将破坏一个空的样本列表并添加 3.
为确保您拥有样本的最新值,您应该将一个函数传递给 setSample
。此函数将从 react 获取最新版本的状态变量。
setSample((latest) => {
return [
...latest,
{
label: list.id,
value: list.id
}
]
});
state updater does batching
并且由于您在 map 中调用 setSample
方法,因此只有您的最后一个值被写入状态。
这里最好的解决方案是return来自地图的数据,然后像下面这样更新一次状态。
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);
另一种解决方案是使用回调方法来更新状态,但必须避免多次调用状态更新。
我试图将状态设置为对象数组,但失败了。
我使用 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>
);
};
我在下面附上了所有测试代码。
这里是codesandboxlink。 https://codesandbox.io/s/zr50rv7qjp
我期待
的结果123
通过点击,但结果是
3
此外,对于额外的点击,预期结果是
123 123
然后我明白了
3 3.
当我使用 setSample() 时,我希望函数类似于 Array.push()。但它忽略了除最后一个之外的所有先前数据。
如有帮助将不胜感激!
您正在破坏 sample
,当您循环和调用 setSample
时,它本身不会有最新版本。这就是为什么它只将 3 放入样本列表中的原因,因为地图的最后一次迭代将破坏一个空的样本列表并添加 3.
为确保您拥有样本的最新值,您应该将一个函数传递给 setSample
。此函数将从 react 获取最新版本的状态变量。
setSample((latest) => {
return [
...latest,
{
label: list.id,
value: list.id
}
]
});
state updater does batching
并且由于您在 map 中调用 setSample
方法,因此只有您的最后一个值被写入状态。
这里最好的解决方案是return来自地图的数据,然后像下面这样更新一次状态。
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);
另一种解决方案是使用回调方法来更新状态,但必须避免多次调用状态更新。