Reputation: 11
I have been working with React Hooks for a while, but the biggest problem for me is working with arrays.
How to update value of nested array of objects? I want to change dropdown type. My code is below and changes the state directly. How can I fix this? What is the most correct code?
Thanks for your help.
const [grups, setGrups] = useState([
{
id: 1,
css: "col",
components: [
{ id: 1, type: "textbox" },
{ id: 2, type: "integer" },
],
},
{
id: 2,
css: "col",
components: [
{ id: 1, type: "numerictextbox" },
**{ id: 2, type: "dropdown" },**
],
},
]);
function handleClick(gindex,cindex) {
const newgrups = [...grups];
newgrups[gindex] = {...grups[gindex] ,components: [...grups[gindex].components]};
newgrups[gindex].components[cindex].tip="datetime";
setGrups(newgrups);
}
Upvotes: 1
Views: 1222
Reputation: 195952
So you need something like
function handleClick(gindex, cindex) {
// use map to create a new array and at the same time
// modify the contents when required
const newgrups = grups.map((grup, gidx) => {
// if the index is not the one we want return the while grup as is
if (gidx !== gindex) return grup;
// otherwise create a new one by spreading the existing
return {
...grup,
// and override the prop which is changed
components: grup.components.map((component, cidx) => {
// again if the component is not the one we want to update
// return it as is
if (cidx !== cindex) return component;
// otherwise create a new one by spreading the existing
// and adding/modifying the props we want
return {
...component,
tip: 'datetime'
}
})
}
});
setGrups(newgrups);
}
If you just want to go with the code you have, you just need to create a new component as well
newgrups[gindex].components[cindex] = { ...newgrups[gindex].components[cindex],
tip: 'datetime'
}
Upvotes: 1
Reputation: 1428
It is good practice to design your state as you would design a database. In a database normalised design is recommended because you can't just nest states in other states. In your case you could split the state in the same way:
grups
[
{
id: 1,
css: "col"
},
{
id: 2,
css: "col"
}
];
components
[
{ grups_id: 1, id: 1, type: "textbox" },
{ grups_id: 1, id: 2, type: "integer" },
{ grups_id: 2, id: 1, type: "numerictextbox" },
{ grups_id: 2, id: 2, type: "dropdown" }
]
This makes it significantly easier to handle the state and avoid nesting and complex procedues. You can easily work with components by applying componenents.filter()
and filter by grups_id.
Upvotes: 0