递归查找节点并递归更改其访问权限



我有这个树数据:

type DataType = {
id: string;
access: 'view' | 'none';
isDisabled: boolean;
children: DataType[];
};
export const Data: DataType = {
id: '1',
access: 'view',
isDisabled: false,
children: [
{
id: '2',
access: 'view',
isDisabled: false,
children: [
{
id: '3',
access: 'view',
isDisabled: false,
children: [],
},
],
},
{
id: '4',
access: 'view',
isDisabled: false,
children: [],
},
{
id: '5',
access: 'view',
isDisabled: false,
children: [],
},
],
};

我想做的是当一个节点的访问改变时,isDisabled布尔值将根据以下规则改变:

如果访问权限为'view', isDisabled将保持false;如果访问权限为'none',当前节点的isDisabled将为false,但其子节点的isDisabled将为true。

我有这些函数:(不像我希望的那样工作)

// this will find the node
const find = (
data: DataType,
selectedId: string,
selectedAccess: 'view' | 'none'
) => {
if (selectedId && selectedAccess) {
if (data.id === selectedId) {
data = changeAccess(data, selectedId, selectedAccess);
} else {
data.children.forEach((child) => find(child, selectedId, selectedAccess));
}
}
};
// this will change the access and isDisabled
const changeAccess = (
data: DataType,
selectedId: string,
selectedAccess: 'view' | 'none'
): DataType => ({
id: data.id,
access: selectedAccess,
isDisabled:
data.id !== selectedId && selectedAccess !== 'view' ? true : false, // condition to toggle the isDisabled
children: data.children?.map((child) =>
changeAccess(child, selectedId, selectedAccess)
),
});

如果我用

来调用find函数
find(Data, '2', 'none');

结果将是:

const DataAfter: DataType = {
id: '1',
access: 'view',
isDisabled: false,
children: [
{
id: '2',
access: 'none', // changed from 'view' to 'none'
isDisabled: false, // remain false
children: [
{
id: '3',
access: 'none', // changed from 'view' to 'none'
isDisabled: true, // changed from false to true
children: [],
},
],
},
{
id: '4',
access: 'view',
isDisabled: false,
children: [
{
id: '5',
access: 'view',
isDisabled: false,
children: [],
},
],
},
],
};

如果我再次调用find:

find(Data, '4', 'none');

结果将是:(注意前面的调用改变了数组,并且在这里也反映了id 2 &3)

const DataAfter2: DataType = {
id: '1',
access: 'view',
isDisabled: false,
children: [
{ // id 2 & 3 remains changed from the pervious call.
id: '2',
access: 'none',
isDisabled: false,
children: [
{
id: '3',
access: 'none',
isDisabled: true,
children: [],
},
],
},
{
id: '4',
access: 'none', // changed from 'view' to 'none'
isDisabled: false, // remain false
children: [
{
id: '5',
access: 'none', // changed from 'view' to 'none'
isDisabled: true, // changed from false to true
children: [],
},
],
},
],
};

如果我用:

find(Data, '1', 'none');

所有的访问将是'none',只有id:1将有它的isDisabled布尔值等于false。

最后,如果我用:

find(Data, '1', 'view');

All access将改为'view', All isDisabled设置为false。

我的功能不像我希望的那样工作。非常感谢您的帮助。

如果你看到了类似的问题,我很抱歉,我对递归和树数据相当陌生,想以不同的方式练习使用它。

这一行:

data = changeAccess(data, selectedId, selectedAccess)

将在data变量中获得一个新对象,但这不会改变原始的data…这是一个重新赋值,丢弃了data之前的引用,并且(因为JavaScript没有按引用调用)调用者将看不到新对象。

当您想改变给定的数据结构时,您不应该让changeAccess返回一个新对象。它应该改变它:

const find = (
data: DataType,
selectedId: string,
selectedAccess: 'view' | 'none'
) => {
if (selectedId && selectedAccess) {
if (data.id === selectedId) {
changeAccess(data, selectedId, selectedAccess); // No return value
} else {
data.children.forEach((child) => find(child, selectedId, selectedAccess));
}
}
};
const changeAccess = (
data: DataType,
selectedId: string,
selectedAccess: 'view' | 'none'
) => Object.assign(data, { // Mutate `data`
access: selectedAccess,
isDisabled:
data.id !== selectedId && selectedAccess !== 'view', // already boolean
children: data.children?.map((child) =>
changeAccess(child, selectedId, selectedAccess)
),
});

最新更新