[英]How to programatically add new children to a deeply nested object
Consider the following object, which is composed by an unknown number of deeply nested children.考虑以下对象,它由数量未知的深度嵌套子项组成。
const state = {
id: 1,
children: [
{
id: 3,
children: [
{
id: 4,
children: []
}
]
},
{
id: 2,
children: []
}
]
}
How can I programatically push a new object to the children
array of a node knowing only its id
and the array of id
s of its parents?我如何编程推向一个新的对象到children
节点的数组只知道它的id
和数组id
的父母第? I thought using recursion but I couldn't find a solution that worked.我想使用递归,但我找不到有效的解决方案。 I am also using immutability-helper, so I have tried using Array.reduce()
to return an object that looked like this:我也在使用 immutability-helper,所以我尝试使用Array.reduce()
返回一个看起来像这样的对象:
const newState = {
children: {
[idxOfNodeToChange]: {
children: {$push: newChildren}
}
}
}
so I could pass it to update()
but there I am even more stuck since I would still have to traverse through the accumulator every time to go as deep as needed, and I'm not sure how to do that.所以我可以将它传递给update()
但在那里我更加卡住了,因为我每次仍然需要遍历累加器才能根据需要深入,我不知道如何做到这一点。 Any ideas?有任何想法吗?
Extra info: I'm using a D3 library for React called VX and this structure is required to build a tree component, so I'm stuck on how to add new nodes programatically.额外信息:我正在使用一个名为 VX 的 React D3 库,构建树组件需要这种结构,所以我一直在思考如何以编程方式添加新节点。
Let's find the node with ID 3 in our state, searching one level deep.让我们在我们的状态中找到 ID 为 3 的节点,搜索一层深。 Take the children of the current node , and find the node with correct ID within those children:取当前节点的子节点,并在这些子节点中找到具有正确 ID 的节点:
id = 3
node3 = state.children.find(v => v == id)
In that node, find ID 4. Now we're searching in the children of node 3 :在该节点中,找到 ID 4。现在我们正在搜索节点 3的子节点:
id = 4 // ┌ act on node3!
node4 = node3.children.find(v => v == id)
Fitting that to Array.reduce()
, the accumulator is the current node .将其拟合到Array.reduce()
,累加器是当前节点。 It starts at the root node state
, and then traverses the tree downwards: each time, we traverse the tree one level, using the next ID from a list of IDs.它从根节点state
,然后向下遍历树:每次,我们使用 ID 列表中的下一个 ID 遍历树一级。 We need the recursion to start at the root of the tree, so the initial value is state
, our root node.我们需要递归从树的根开始,所以初始值是state
,我们的根节点。
If we take the above examples and reduce
them:如果我们采用上面的例子并reduce
它们:
[3, 4].reduce((acc, x) => acc.children.find(v => v === x), state)
// ids traverse one level start at root node
Unrolling it, this is equivalent to:展开它,这相当于:
(state.children.find(v => v === 3)).children.find(v => v === 4)
The general form becomes:一般形式变为:
const recursiveTraversal = ids =>
ids.reduce((acc, x) => acc.children.find(v => v === x), state)
Here you go.干得好。 You can use this recursive function to search by id and append data to the found node's children array.您可以使用此递归函数按 id 搜索并将数据附加到找到的节点的 children 数组。
function appendChildToNode(node, nodeId, data) {
// If the node is empty, just return it as is.
if (!node) {
return node;
}
let children;
if (node.id === nodeId) {
// If the node has the id we're searching for,
// append the data to its children.
children = [...node.children, data];
} else {
// Otherwise, apply the function recursively to each of its children
children = node.children.map(childNode => appendChildToNode(childNode, nodeId, data));
}
return { ...node, children };
}
It is immutable and you may use it like this:它是不可变的,你可以这样使用它:
const newState1 = appendChildToNode(state, 4, { id: 5, children: [] });
const newState2 = appendChildToNode(state, 2, { id: 5, children: [] });
See it working in the example snippet below.在下面的示例片段中查看它的工作情况。
const state = { id: 1, children: [{ id: 3, children: [{ id: 4, children: [] }] }, { id: 2, children: [] } ] }; const newState1 = appendChildToNode(state, 4, { id: 5, children: [] }); const newState2 = appendChildToNode(state, 2, { id: 5, children: [] }); console.log(state); // Orginal state should not be mutated. console.log(newState1); console.log(newState2); function appendChildToNode(node, nodeId, data) { // If the node is empty, just return it as is. if (!node) { return node; } let children; if (node.id === nodeId) { // If the node has the id we're searching for, // append the data to its children. children = [...node.children, data]; } else { // Otherwise, apply the function recursively to each of its children children = node.children.map(childNode => appendChildToNode(childNode, nodeId, data)); } return { ...node, children }; }
Update: The above function uses ES6 spread syntax to append items.更新:上述函数使用ES6 扩展语法来附加项目。 If you need to support older browsers w/o transpilation, you can use this updated version using Object.assign
and Array#concat
.如果你需要支持没有转译的旧浏览器,你可以使用这个更新版本使用Object.assign
和Array#concat
。
function appendChildToNode(node, nodeId, data) {
if (!node) {
return node;
}
var children;
if (node.id === nodeId) {
children = node.children.concat([data]);
} else {
children = node.children.map(childNode => appendChildToNode(childNode, nodeId, data));
}
return Object.assign({}, node, { children });
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.