da1367439622 2021-04-20 16:21 采纳率: 100%
浏览 40
已采纳

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;
  • 写回答

2条回答 默认 最新

  • da1367439622 2021-04-22 16:26
    关注

    自问自答,代码仅供参考!!!!!!!!!!!!!!!!!!

    关键点:注意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;
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(1条)

报告相同问题?

悬赏问题

  • ¥15 虚幻5 UE美术毛发渲染
  • ¥15 CVRP 图论 物流运输优化
  • ¥15 Tableau online 嵌入ppt失败
  • ¥100 支付宝网页转账系统不识别账号
  • ¥15 基于单片机的靶位控制系统
  • ¥15 真我手机蓝牙传输进度消息被关闭了,怎么打开?(关键词-消息通知)
  • ¥15 装 pytorch 的时候出了好多问题,遇到这种情况怎么处理?
  • ¥20 IOS游览器某宝手机网页版自动立即购买JavaScript脚本
  • ¥15 手机接入宽带网线,如何释放宽带全部速度
  • ¥30 关于#r语言#的问题:如何对R语言中mfgarch包中构建的garch-midas模型进行样本内长期波动率预测和样本外长期波动率预测