专栏首页一Li小麦树形结构踩坑记

树形结构踩坑记

树形结构数据的查询、渲染和删除是一类常见的问题。

初始问题:如何从树形结构中检索数据

两个月前有个初级前端卡在这个需求。现有数据结构如下:

const data = [{
    id: 9,
    title: 'Node2',
}, {
    id: 1,
    title: 'Node1',
    children: [{
        id: 2,
        title: 'Child Node1',
    }, {
        id: 3,
        title: 'Child Node2',
    }, {
        id: 4,
        title: 'Child Node2',
        children: [{
            id: 5,
            title: 'Child Node1',
        }, {
            id: 6,
            title: 'Child Node2',
        }, {
            id: 7,
            title: 'Child Node7',
        },]
    },]
}, {
    id: 8,
    title: 'Node2'
}]

如何查询指定id下的data?

我给出递归的方案:

const findOne = (_data, id) => {
    let i = 0;
    let result = null;
    while (i < _data.length) {
        if (_data[i].id == id) {
            result = _data[i];
            break;
        } else if (_data[i].children&& findOne(_data[i].children, id)) {
            return findOne(_data[i].children, id);
        } else {
            i++;
        }
    }
    return result
}

//测试
console.log(findOne(data, 5))

函数将返回指定id下的所有数据。

在react中如何渲染树结构

项目以 antD为例:

这个数据结构,除了章节节点之外还有习题,最初后端给出的是两个表联查得出的数据结构:

习题放在了和children同层级的resource中。children对应的id为value,resource对应的为resourceid。

而标准的渲染,是必须把习题也放入到children中的。

// 渲染树形结构
  renderTree(arr, parentNode) {
    let cHtml = <div></div>;
    let _this = this;
    arr = arr.map((x, i) => {
      if (x.children) {
        x.children = x.children.concat(x.rescourse)
        // console.log(x)
        return <TreeNode 
        key={x.value} 
        title={<span>{x.label}&nbsp;&nbsp;<a style={{
          color: 'rgb(255,150,50)'
        }} href="javascript:;" onClick={(e) => {
          e.stopPropagation();
          this.nodeoOnEdit(x)
        }}><Icon type="edit" /></a>
          &nbsp;&nbsp;<a style={{
            color: 'rgb(241,102,82)'
          }} href="javascript:;" onClick={(e) => {
            e.stopPropagation();
            this.nodeoOnDel(x)
          }}><Icon type="delete" /></a>
        </span>} >{_this.renderTree(x.children, x.value)}</TreeNode>
      } else {
        return <TreeNode
          key={arr[i].value}
          // key={parentNode} 
          title={<span>{arr[i].title}&nbsp;&nbsp;<a style={{
            color: 'rgb(241,102,82)'
          }} href="javascript:;" onClick={(e) => {
            e.stopPropagation();
            this.unitDataOnDel(x, parentNode)
          }}><Icon type="delete" /></a></span>}
          isLeaf />
      }
    })

    return arr;
  }

解决要点:

  • 每次做循环的时候,把resource衔接children上去!
  • 如果没有chilren,进入渲染流程。否则进入递归迭代。

如果我把请求后获取的数据作为 renderTree的参数,势必造成state的改变。

这里需要用到一个hack,就是每次渲染都用深度拷贝的数据。深度拷贝的方法有很多种,也被用来出题。而最简单的:

let new_obj=JSON.parse(JSON.stringify(obj))

如果不考虑性能,这个操作也是逆天的。

删除树形结构

按理来说,后端操作这个是最快的。前端只需要指定一个id即可。

结果后端设计结构时把他们设计为两个表了。删除变得异常复杂。因此需要前端告诉他树形节点的所有id。

因此需要更好的完善 renderTree

这里就用到了 findOne方法。

核心方法如下:

getValue(obj, new_arr) {
    try {
      new_arr.push(obj.value)
    } catch (error) {
      console.log(new_arr)
    }
    if (obj.children) {
      for (let i = 0; i < obj.children.length; i++) {
        this.getValue(obj.children[i], new_arr)
      }
      return new_arr
    }
  }

与之前的相比,这个方法多了一个初始值为 []的参数 new_arr.作为递归的累加器(数组)。每次循环递归渲染,都会记录所有的节点id。

在删除方法中这么写:

let aaa = this.findOne(this.state.courseData, x.value);
aaa = this.getValue(aaa, [])

那么就得到了一个id列表。发给后端,他就可以愉快的删除了。

小结与不足

所有一系列问题的核心在于,后端采用了两个表来设计。树的结构有可能拥有一样的value。这是比较蛋疼的事情。

那么留作思考的问题来了:

应如何组织数据结构,才能很快的实现value值的不冲突呢?

本文分享自微信公众号 - 一Li小麦(gh_c88159ec1309),作者:一li小麦

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-03-28

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • webpack工程化及其配置指北(1)

    现在前端脚手架工具已经非常智能化了。早年刚入行我曾经自己在项目里配过webpack,上午面向百度配置的内容,下午就重复不出来了。后来查了一个下午,才去看pack...

    一粒小麦
  • 从算法看背包问题(1)

    有 N件物品和一个容量为C的背包。第i件物品的重量(即体积,下同)是 W[i],价值是 V[i]。求解将哪些物品装入背包可使这些物品的费用总和不超过背包容量,且...

    一粒小麦
  • h5 补白(1)

    它是一种软件,用来制作网页游戏、动画,以及视频播放器。只要观看网络视频,基本都会用到它。

    一粒小麦
  • 在云原生应用程序体系结构中需要重塑策略和授权的三种趋势

    应用程序开发市场正在转向容器化的“云原生”应用程序架构,而不是单片应用程序。现在也是制定政策和授权的时候了,以提供所有现代安全策略的基础。

    静一
  • 腾讯发布:2017互联网科技创新白皮书

    作者:腾讯研究院 11月8日上午,以“开放·创想”为主题的2017腾讯全球合作伙伴大会在成都开幕在大会现场,腾讯研究院与腾讯开放平台共同发布了《2017互联网...

    钱塘数据
  • 04-老马jQuery教程-DOM节点操作及位置和大小

    DOM时代我们通过document的createElement方法动态创建标签。创建标签后,动态的给他添加属性。例如代码:

    老马
  • 红帽子RHCS套件安装与配置(一)

    RHCS提供的三个核心功能  高可用集群是RHCS的核心功能。当应用程序出现故障,或者系统硬件、网络出现故障时,应用可以通过RHCS提供的高可用性服务管理组件...

    BG彪
  • 标准W3C盒子模型和IE盒子模型CSS布局经典盒子模型(转)

    大当家
  • Zookeeper Python调用

    安装:pip install kazoo 1、链接 from kazoo.client import KazooClient

    用户5760343
  • 深度学习应用实践指南:七大阶段助你创造最佳新应用

    选自arXiv 作者:Leslie N. Smith 机器之心编译 参与:Jane W、黄小天 近日来自美国海军研究室人工智能应用研究中心的 Leslie N...

    机器之心

扫码关注云+社区

领取腾讯云代金券

玩转腾讯云 有奖征文活动