无法递归删除对象数组中的对象
const arr = [
{
id: "8bfc-2b82-68ad-fb78",
name: "inventory",
type: "directory",
path: "inventory/",
children: [
{
id: "bccf-3788-6ec9-ba33",
name: "inventory.yaml",
type: "file",
path: "inventory/inventory.yaml",
},
],
},
{
id: "4a28-4d63-6c30-4569",
name: "model",
type: "directory",
path: "model/",
children: [
{
id: "21d1-f4d2-e1c5-34b0",
name: "model.yaml",
type: "file",
path: "model/model.yaml",
},
],
},
];
function _worktreeItemDelete({ detail }) {
const currentId = detail.item.id;
const filtered = this.tree.filter(entry => entry.id !== currentId);
const updTree = filtered.map(entry => {
if (!entry.children) return entry;
return {...entry, children: this._worktreeItemDelete(entry.children, currentId)};
});
console.log(updTree);
this.set("tree", updTree);
}
这就是我正在做的。
currentId
我正在作为事件属性值捕获。
我现在遇到的问题是:
Uncaught RangeError: Maximum call stack size exceeded
如果我理解正确的话,递归不会停止,正在寻找一种方法来处理这个问题。 感谢您的帮助。
function removeById(arr, id) {
return arr.filter(item => {
arr.children = arr.children && removeById(arr.children);
return item.id !== id;
});
}
您可以在代码中使用此辅助函数
const filtered = removeById(this.tree, currentId);
这是使用 object-scan 的迭代解决方案。使用库来处理您的用例可能有点过头了,但如果需要的话,它可能会使维护该功能变得容易得多。
例如,调整它以允许删除非唯一 ID 只需要删除中止标志。
// const objectScan = require('object-scan');
const myArr = [{ id: '8bfc-2b82-68ad-fb78', name: 'inventory', type: 'directory', path: 'inventory/', children: [{ id: 'bccf-3788-6ec9-ba33', name: 'inventory.yaml', type: 'file', path: 'inventory/inventory.yaml' }] }, { id: '4a28-4d63-6c30-4569', name: 'model', type: 'directory', path: 'model/', children: [{ id: '21d1-f4d2-e1c5-34b0', name: 'model.yaml', type: 'file', path: 'model/model.yaml' }] }];
const removeById = (arr, id) => objectScan(['**(^children$).id'], {
useArraySelector: false,
filterFn: ({ value, gparent, gproperty }) => {
if (value === id) {
gparent.splice(gproperty, 1);
return true;
}
return false;
},
abort: true,
rtn: 'bool'
})(arr);
console.log(removeById(myArr, '21d1-f4d2-e1c5-34b0'));
// => true
console.log(myArr);
/* =>
[
{
id: '8bfc-2b82-68ad-fb78',
name: 'inventory',
type: 'directory',
path: 'inventory/',
children: [
{
id: 'bccf-3788-6ec9-ba33',
name: 'inventory.yaml',
type: 'file',
path: 'inventory/inventory.yaml'
}
]
},
{
id: '4a28-4d63-6c30-4569',
name: 'model',
type: 'directory',
path: 'model/',
children: []
}
]
*/
.as-console-wrapper {max-height: 100% !important; top: 0}
<script src="https://bundle.run/[email protected]"></script>
免责声明 :我是 object-scan
的作者修复函数
您已经接近了。问题在于,您将一个对象传递给初始删除调用,提取嵌套属性
id
以便正确使用,但随后在进行递归调用时,您只使用该 id,而不是整个对象。
最快的修复方法可能是保留对该对象的引用,而不是在参数中对其进行解构。我对上下文的了解还不够,无法正确命名,所以我就将其称为
foo
。然后我们可以将
foo
传递给递归调用,它就会正常工作。
修复后,您的函数变体将正常工作:
function _worktreeItemDelete(tree, foo) {
const currentId = foo.detail.item.id;
const filtered = tree.filter(entry => entry.id !== currentId);
const updTree = filtered.map(entry => {
if (!entry.children) return entry;
return {...entry, children: _worktreeItemDelete(entry.children, foo)};
});
return updTree
}
const arr = [{id: "8bfc-2b82-68ad-fb78", name: "inventory", type: "directory", path: "inventory/", children: [{id: "bccf-3788-6ec9-ba33", name: "inventory.yaml", type: "file", path: "inventory/inventory.yaml", }]}, {id: "4a28-4d63-6c30-4569", name: "model", type: "directory", path: "model/", children: [{id: "21d1-f4d2-e1c5-34b0", name: "model.yaml", type: "file", path: "model/model.yaml"}]}]
console .log (
_worktreeItemDelete (arr, {detail: {item: {id: 'bccf-3788-6ec9-ba33'}}})
)
.as-console-wrapper {max-height: 100% !important; top: 0}
请注意,我将其更改为纯函数而不是方法,因此跳过了
this.set("tree", updTree)
,添加了
tree
参数,并删除了
this
引用。它们应该很容易放回去。
但是 ,以上内容并未解释您描述的递归深度错误。我期望更像这样的内容
Cannot read property 'item' of undefined
因此可能会发生其他事情。
替代方法
我会以不同的方式编写此代码。我将使用通用版本的树过滤函数,并向其传递节点选择的谓词。
我的版本可能如下所示:
const deepFilter = (pred) => (xs) =>
xs .flatMap (({children = [], ...rest}) =>
pred (rest)
? [{... rest, children: deepFilter (pred) (children)}]
: []
)
const removeById = ({detail: {item: {id: target}}}) =>
deepFilter (({id}) => id !== target)
const arr = [{id: "8bfc-2b82-68ad-fb78", name: "inventory", type: "directory", path: "inventory/", children: [{id: "bccf-3788-6ec9-ba33", name: "inventory.yaml", type: "file", path: "inventory/inventory.yaml", }]}, {id: "4a28-4d63-6c30-4569", name: "model", type: "directory", path: "model/", children: [{id: "21d1-f4d2-e1c5-34b0", name: "model.yaml", type: "file", path: "model/model.yaml"}]}]
console .log (
removeById ({detail: {item: {id: 'bccf-3788-6ec9-ba33'}}}) (arr)
)
.as-console-wrapper {max-height: 100% !important; top: 0}
请注意,
deepFilter
是通用的。它适用于后代节点位于属性
children
中的任何树。(请参阅
另一个答案
,了解允许您配置此属性的更通用的版本。)
因此,此处的自定义代码只是
removeById
。在我看来,这是一个不错的胜利。
如果它很重要,我们可以——以增加一点复杂性为代价——选择仅在数据不为空时包含
children
节点。如果您想要这样做并需要帮助,只需添加评论即可。