在开发中,如果有展示公司层级、学科系统、分类目录的需求的话,就经常会需要将对象数组的结构转成树型结构,然后应用到antd组件里,比如Tree树形控件、TreeSelect树形选择器、树形数据展示的Table等。
Tree
TreeSelect
Table
只需要将数据转换成如下结构即可:
转换之前就是一普通对象数组
递归遍历,时间复杂度可能略高,但是我这里数据层级不超过三四层,所以还好。转换的代码如下:(转换成table需要的树形数据)
useEffect(() => {
const x = testMenu; //要转换的数据
setLoading(true);
const resultTemp = arrayToTree(x, -1);
const result = deleteChildren(resultTemp);
//console.log(result)
setData(result);
setLoading(false);
setExpandKeys(tempExpandKey.current);
}, []);
const count = useRef<number>(1);
const tempExpandKey = useRef<React.Key[]>([]); //保存树所有的key
const getChildren = (data2: MenuManageType[], result: MenuManageType[], pId: number) => {
if (pId >= -1) {
for (const item of data2) {
if (item.parentId === pId) {
const newItem = {
id: item.id,
name: item.name,
url: item.url,
path: item.path,
css: item.css,
sort: item.sort,
type: item.type,
keyValue: count.current,
children: [],
};
result.push(newItem);
count.current++;
getChildren(data2, newItem.children, item.id);
}
}
}
};
const arrayToTree = (data1: MenuManageType[], pId: number) => {
const result: MenuManageType[] = [];
getChildren(data1, result, pId);
return result;
};
//带children渲染table,children为[]也会有+展开符 需要删掉children字段。不知道如何优化
const deleteChildren = (data3: MenuManageType[]) => {
const childTemp: MenuManageType[] = data3;
//console.log(childTemp)
for (let i = childTemp.length; i >= 0; i--) {
if (childTemp[i] && childTemp[i].children) {
if (childTemp[i].children?.length) {
tempExpandKey.current.push(childTemp[i].id);
deleteChildren(childTemp[i].children);
} else {
delete childTemp[i].children;
}
}
}
return data3;
};
写的很烂,大佬如果有修改意见,请尽管提出。
如果想要table的树形结构在第二列展开可以加一行,不过文档中好像没有给出
expandIconColumnIndex={1}
总结:对象数组扁平化转成树形结构这个算法还挺常用的,还可以继续优化一下,不用递归,时间复杂度太高,还可以提取出来做成一个通用的函数。