I want to update the state using react Hooks useState(); ?
Here is an example :
I have global state on top of the app:
const [familyTree, setFamilyTree] = useState([
{
fam_id: 1,
name: "No name",
attributes: {
"Key1": "*",
"Key2": "*",
},
children: [
{
fam_id: 2,
name: "No Name2",
attributes: {
"Key1": "*",
"Key2": "*",
},
},
],
},
]);
I have a current object to update the global state:
let res = {
fam_id: 2,
name: "No Name2",
attributes: {
"Key1": "Update this",
"Key2": "*",
},
},
Recursive function in this case helps me to update global state with matched ID, but I have problem now,
const matchAndUpdate = (updater, target) => {
if (updater.fam_id === target.fam_id) {
target.name = updater.name;
target.attributes = updater.attributes;
}
if ("children" in target && Array.isArray(target.children)) {
target.children.forEach((child) => {
matchAndUpdate(updater, child);
});
}
};
familyTree.forEach((g) => {
matchAndUpdate(res, g);
setFamilyTree({ ...g }); // here is my try, this works on start, but on secound update i got error about forEach is not a function...
});
I don't know where to update state on correct way?
Thanks, o/
Because you update state inside of forEach().
Maybe you should use .map and update state then at the end of check array.
This is the solution:
const matchAndUpdate = (updater, children) => {
return children.map(_child => {
if (updater.fam_id === _child.fam_id) {
return {
...updater,
children: _child.children && Array.isArray(_child.children) ? matchAndUpdate(updater, _child.children) : null
};
} else {
return {..._child,children: _child.children && Array.isArray(_child.children) ? matchAndUpdate(updater,_child.children) : null};
}
});
};
This will return and array of children, so you will begin from the initial array:
const finalFamily = matchAndUpdate({ fam_id: 1, name: "Name" }, familyTree);
finalFamily will be the final updated array.
You can update the state like this:
// Option 1:
setFamilyTree(matchAndUpdate({ fam_id: 1, name: "Name" }, familyTree);
// Option 2:
const newFamilyTree = matchAndUpdate({ fam_id: 1, name: "Name" }, familyTree);
setFamilyTree(newFamily);
--- NEXT QUESTION-- -
I understand that you want to create a method to push new children to child specified by id.
I developed a method that maintains attributes and old children:
const addChildrenToChild = (parent,numChildren) => {
const arrayChildren = [];
for (let i = 0; i < numChildren; i++) {
arrayChildren.push({
fam_id: Math.floor(Math.random() * 100),
name: "No name",
attributes: {
key1:"",
key2:""
},
});
}
return {...parent,children:parent.children && Array.isArray(parent.children) ? parent.children.concat(arrayChildren) : arrayChildren }
}
And upgrade matchAndUpdate to maintains old children
const matchAndUpdate = (updater, children) => {
return children.map(_child => {
if (updater.fam_id === _child.fam_id) {
return {
...updater,
children: updater.children
//Filter updater children
.filter(_childFiltered =>
_child.children && Array.isArray(_child.children) ?
//check if exists new child in old children
_child.children.some(
_childToCheck => _childToCheck.fam_id !== _childFiltered.fam_id
) : true
)
//concat old children and check to update
.concat(
_child.children && Array.isArray(_child.children)
? matchAndUpdate(updater, _child.children)
: []
)
};
} else {
return {
..._child,
children:
_child.children && Array.isArray(_child.children)
? matchAndUpdate(updater, _child.children)
: []
};
}
});
};
And now. You can use the other method at the same time to add new children:
// Now we are going to add new children to the first element in familyTree array, and maintains old children if it has.
const newFamilyTree = matchAndUpdate(
addChildrenToChild(familyTree[0], 10),
familyTree
);
setFamilyTree(newFamilyTree);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With