/*
实现一个循环引用树形组件
要求:
1. 要考虑数据循环引用问题。
2. 除了 React,Antd 外,不能使用任何第三方库,只能使用浏览器原生 API
如:存在三条数据 A、B、C:
- A 的子元素为 B、C
- B 的子元素为 C、A
- C 的子元素为 A、B
则构成 A -> B -> C -> A 的循环引用。
渲染结果如下图所示,其中每个节点都可以展开,且可以无限递归展开。
https://s3plus.meituan.net/v1/mss_bf7e9f1c1cc54cfb819fc8ffcf965b40/static/WX20201209-113933%402x.png
*/
import React, { useState } from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import { Tree } from "antd";
const a = { id: 1, title: "A" };
const b = { id: 2, title: "B" };
const c = { id: 3, title: "C" };
const d = { id: 4, title: "D" };
const e = { id: 5, title: "E" };
const f = { id: 6, title: "F" };
const g = { id: 7, title: "G" };
a.children = [b, d, e];
b.children = [c, e, f];
c.children = [e, g, a];
d.children = [e, f, g];
e.children = [a, b, c];
f.children = [c, d, e];
g.children = [b, e, f];
const data = [a, b, c, d, e, f, g];
const ROOT = 0;
const Demo = () => {
const [entities] = useState(() => {
return [a, b, c, d, e, f, g].reduce((r, d) => {
r[d.id] = d;
return r;
}, {});
});
const [childrenMap, setChildrenMap] = useState(() => {
return {
[ROOT]: data.map((d) => ({
id: d.id,
title: d.title,
key: Math.random()
}))
};
});
const onLoadData = React.useCallback((parent) => {
return new Promise((resolve) => {
if (parent.children) return resolve();
setTimeout(() => {
});
});
}, []);
const treeData = React.useMemo(() => {
const iter = (children) => {
if (!children) return;
return children.map(({ key, id }) => {
const item = entities[id];
if (!item) return null;
return null;
});
};
return iter(childrenMap[ROOT]);
}, [entities, childrenMap]);
return <Tree loadData={onLoadData} treeData={treeData} />;
};
export default Demo;
自问自答,代码仅供参考!!!!!!!!!!!!!!!!!!
关键点:注意onLoadData函数在调用时,antd会传入的值,一开始我没找到,返回去看,demo时发现里面传了一个origin,这个origin,应该时当前的treeData树,所以异步加载时,直接重构原treeData,为指定的节点加载children。
这个题和antd上的Demo,方法异同,
import React, { useState } from "react";
// import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import { Tree } from "antd";
/*
实现一个循环引用树形组件
要求:
1. 要考虑数据循环引用问题。
2. 除了 React,Antd 外,不能使用任何第三方库,只能使用浏览器原生 API
如:存在三条数据 A、B、C:
- A 的子元素为 B、C
- B 的子元素为 C、A
- C 的子元素为 A、B
则构成 A -> B -> C -> A 的循环引用。
渲染结果如下图所示,其中每个节点都可以展开,且可以无限递归展开。
https://s3plus.meituan.net/v1/mss_bf7e9f1c1cc54cfb819fc8ffcf965b40/static/WX20201209-113933%402x.png
*/
const a = { id: 1, title: "A" };
const b = { id: 2, title: "B" };
const c = { id: 3, title: "C" };
const d = { id: 4, title: "D" };
const e = { id: 5, title: "E" };
const f = { id: 6, title: "F" };
const g = { id: 7, title: "G" };
a.children = [b, d, e];
b.children = [c, e, f];
c.children = [e, g, a];
d.children = [e, f, g];
e.children = [a, b, c];
f.children = [c, d, e];
g.children = [b, e, f];
const data = [a, b, c, d, e, f, g];
const ROOT = 0;
const Demo = () => {
const [entities] = useState(() => {
return [a, b, c, d, e, f, g].reduce((r, d) => {
r[d.id] = d;
return r;
}, {});
});
const [childrenMap, setChildrenMap] = useState(() => {
return {
[ROOT]: data.map((d) => ({
id: d.id,
key: Math.random()
}))
};
});
const onLoadData = React.useCallback((parent) => {
return new Promise((resolve) => {
if (parent.children) return resolve();
setTimeout(() => {
setChildrenMap((origin) => {
console.log("promise中的childrenMap",origin,"****",childrenMap);
return {
...origin,
[parent.key]:entities[parent.id].children.map(({id,title})=>{
return{
id:id,
title:title,
key:Math.random()
}}),
}
});
resolve();
},500);
});
}, []);
const treeData = React.useMemo(() => {
console.log(childrenMap);
const iter = (children) => {
if (!children) return;
console.log("useMemo",children);
return children.map(({ key, id }) => {
const item = entities[id];
if (!item) return null;
return { id: id, key: key, title: item.title,children:iter(childrenMap[key])};
});
};
return iter(childrenMap[ROOT]);
}, [entities,childrenMap]);
console.log(childrenMap);
return <Tree loadData={onLoadData} treeData={treeData} />;
};
export default Demo;
你好,我是有问必答小助手,非常抱歉,本次您提出的有问必答问题,技术专家团超时未为您做出解答
本次提问扣除的有问必答次数,将会以问答VIP体验卡(1次有问必答机会、商城购买实体图书享受95折优惠)的形式为您补发到账户。
因为有问必答VIP体验卡有效期仅有1天,您在需要使用的时候【私信】联系我,我会为您补发。