28 我被骂了,但我学会了如何构造高性能的树状结构 - AnnGreen1/article GitHub Wiki
我被骂了,但我学会了如何构造高性能的树状结构
mp.weixin.qq.com快跑啊小卢 前端之神
☀️ 前言
- 大家好我是小卢,是不是经常见到这样的**「树状结构」,我们有时需要对这个结构进行“「添加」,「删除」,「修改」**”等处理,但每每遇到这种结构就会很容易出错。
-
小卢:大佬,这种树状结构我做数据处理好麻烦呀,又要遍历又要拆解,而且好容易出错。
-
大佬:你白痴啊,你直接拍扁不就好了?
-
大佬:这是你自己的问题吧,写得这么**「烂」**。
-
小卢:拍...拍扁?对喔
🤔 奇妙的扁平树状结构
-
我们平时见到的树状结构一般都是这样的,每层数组中的
item
都会有一个children
,里面嵌套一个数组然后每个子item
也还会有各自的children
,就这样一直嵌套下去。 -
而拍扁后的树状结构其实是一个对象,每个
item
都扁平化平铺在第一层,每一个item
都有各自的parentId
与childrenIds
。
❓ 有什么不同
父节点
-
在第一种结构中其实没有专门的根节点,在最外层的数组中每一项都是第一层级的父节点。
-
而在第二种结构中一般都会有一个
item
专门来表示**「根节点」**,就比如这个对象第一行id
为root
的item
。
子节点
-
在第一种结构中我们的子节点都是在父节点的
children
数组下的每一项,而每一项还会有各自的子节点存在于对应的children
中。 -
而在第二种结构中每一项都可以当成是子节点,他们各自都拥有一个
parentId
,而**「根节点」**的parentId
为空代表它没有父节点,他们的各自的childrenIds
存储了他们各自item
的子节点id
。
渲染
- 就拿
react
来举例,我们一般渲染一个列表都是通过map
进行遍历渲染,拿到对应的item
通过itemRender()
来处理对应的ReactNode
,在渲染中其实两种状态的使用相差不大。
添加
-
在数组对象形式中我们需要给一个父节点添加一个子节点我们首先需要拿到这个父节点的
key
,然后对整个数组结构进行遍历查找来找到对应的item
拎出来push
进他的children
中,然后需要重新构造一个新的数组对象。 -
由于实在是太麻烦了我就列了大概思路,相信大家都会,我们会发现非常繁琐,接下来我会着重讲一下
Map
形式。 -
而在
Map
形式中我们不需要递归循环遍历整课树,可以发现,在整个结构中数据的表现是非常清晰的,每个item
都是一样的。 -
我们首先在
Map
新增一条子项数据,直接放在数据结构末尾即可,然后我们再给对应的父节点
的childrenIds
中push
这个子项的id
即可。 -
和上面那种形式对比感觉如何呢,我个人感觉是方便太多了。
修改
-
在数组对象形式中我们想修改某一个节点的
title
的时候,我们需要根据key
遍历找出这个节点然后修改最后构造新的数组结构。 -
而在
Map
形式我们拿到想修改的id
后就可以直接修改。
删除
-
在数组对象形式中我们需要删除一个节点的时候,还是很繁琐,先遍历再删除构造新的数组,想想都已经很麻烦了。
-
而在
Map
形式中我们直接delete
对应id
的项即可,如果该项有父节点,我们可以在对应parentId
项中的childrenIds
移除对应的id
即可。
👋 写在最后
-
我们可以发现将整个结构扁平化后收益特别多。
-
结构很清晰,我们可以很**「轻易」的对数据进行「处理」**。
-
特别是在特别大数据量的情况下,这种形式可以极大的**「提高性能」**,减去需要遍历的性能消耗。
-
以前各种在数组对象出现的弊端都消失了。
-
这下我知道为什么之前会被大佬骂了,但是我也变强了,这次记录一下分享给大家,希望对大家有帮助。
-
这次的文章就分享到这里,有需要可以点赞收藏喔,我是小卢,想要了解更多关于程序员的知识欢迎关注我。
-
「如果想跟我一起讨论和学习更多的前端知识可以加入我的前端交流学习群,大家一起畅谈天下~~~」