In this scenario, I usually use a Map referencing the items within the nested arrays. For example:
const items = [
{
id: 1,
name: "Test name",
children: [
{
id: 5,
name: "Test name 5",
children: [
{
id: 6,
name: "Test name 6",
children: [],
},
],
},
],
},
{
id: 8,
name: "Test name 8",
children: [
{
id: 9,
name: "Test name 9",
children: [],
},
],
},
];
const createItemsMap = items => {
const m = new Map();
(function _collect(items) {
for (const item of items) {
m.set(item.id, item);
if (item.children) {
_collect(item.children);
}
}
})(items);
return m;
}
const itemsMap = createItemsMap(items);
// modify item #6
itemsMap.get(6).name = "Modified name 6";
console.log("itemsMap.get(1) === items[0] is", itemsMap.get(1) === items[0]);
console.log(items);
With that map, modifying the items is simply a matter of doing this :
const keys = [1,5,6];
for (const key of keys)
const item = itemsMap.get(key);
// update item
item.name = `Updated name ${key}`;
item.newProp = 'New value!';
}
// ex:
console.log(items[0]);
// {
// id: 1,
// name: "Updated name 1",
// newProp: "New value!',
// children: [
// {
// id: 5,
// name: "Updated name 5",
// newProps: "New value!",
// children: [
// {
// id: 6,
// name: "Updated name 6",
// newProps: "New value!",
// children: [],
// },
// ],
// },
// ],
// },
And a few more freebies :
// get all existing keys
const keys = Array.from(itemsMap.keys());
// check if an item exists
const exists3 = itemsMap.has(3); // false
const exists5 = itemsMap.has(5); // true
// adding new children
const newChild = { id: 3, name: "Test name 3", children: [] };
// ... add as child of 5
itemsMap.get(5).children.push(newChild);
// ... add it to the map
itemsMap.set(newChild.id, newChild); // that's it!
// remove an item
const removed = itemsMap.get(3);
// ... find if there is a parent...
const parent = Array.from(itemsMap.values()).find(item =>
item.children.includes(removed)
);
if (parent) {
// ... if there is a parent, remove the child
parent.children = parent.children.filter(item =>
item !== removed
);
} else {
// ... otherwise it is a root item, so remove it
items = items.filter(item => item !== removed);
}
// ... remove from map
itemsMap.delete(removed.id);
Note: If items is modified directly (i.e. items are added or removed), then itemsMap needs to either be re-generated, or preferably updated. In any other case, both items and itemsMap reference to the same data.