react相关技术请求,一道面试题,

/*

实现一个循环引用树形组件

要求:

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天,您在需要使用的时候【私信】联系我,我会为您补发。