树形选择器的使用场景探索
在工作中,树形选择器(tree-select)是一种常见的基础组件, 这次我们针对此组件做一些业务适配
背景:
在一个大型组织(2 万以上)内,需要有一个选择人、组的一个选择器, 支持搜索功能。

一开始我的思路是这样:
层级加载+后端搜索
既然数据量很多,那最好不要一次性加载,不然会有以下的一些问题:
问题一是后端的加载速度很慢
二是前端也会手动很大的影响,比如需要开启虚拟列表,选中的值传递、处理、展示需要修改。
所以先定只加载第一层数据,其他数据懒加载,点开时请求后端接口,加载下一层级的数据;关于搜索则需要使用关键字参数来通过接口获取数据,将这些数据全部替换当前的数据。
但是这样设计的话,问题也随之而来:
在搜索数据之后选中某个值,之后退出搜索模式,选中的值没有对应的 title,显示成key 了
const [value, setValue] = useState(['0-0-0-1']);

针对此种情况,我发动了脑筋,首先想到的解决办法是:
搜索合并
在搜索出结果时,将结果插入原有的数中:

这里需要一个算法,即树的合并,同时在原有已有数据的场景下,也要根据 id 去重
在两棵树合并之后,还需要借助 tree-select 自身的前端搜索能力(即开启 optionFilter),将结果筛选出来
这将是一个完整的懒加载+搜索能力的树形选择器了
即使如此,还依旧存在着问题:
问题1:全选和半选的显示
在出现搜索的时候,如果我选中 A 组下的 1 , 那 A 是不是应该是全选,但是组件怎么知道还有 2,3 呢,这时候还没有懒加载出来

这种场景下,antd 里并没有类似半选全选的参数,除了魔改源码(通过后端基于参数来知晓是否全选半选)以外暂无其他方案
问题2: 初始值显示
假如通过了全选半选的方案,可以说在保存模式下一件是成功了,但是在编辑的模式下依旧存在着初始值显示的问题,即之前选择的值是 lazy 加载的,但是初始状态下数据源中无值
存储节点名
这时候我想到了官方的 API labelInValue,  于是我尝试了一把:
const [value, setValue] = useState([{id:'0-0-0-1',label:'员工张三'}]);

很明显的,他将名称存储到值里确实能够生效,但是也带来了问题:
数据的传递,存储会更吃力
原本只需要 id ,(可能还需要带上 path 路径)的简单数据,现在需要完整的 title,而且变成了对象结构
并且还有一个小问题:
labelInValue 模式下的 label 值,优先级更高与 dataSource 的 value
所以在某个人员的数据变更后(即数据源中的数据更加新),显示的值仍旧是一个旧值

忽略这两小问题,可以说选择+回显正常了,不过事实证明我高兴得太早了
接口请求
当前初始值的显示这一切都可以使用接口请求来完成,但是如果层级较深,又或者界面上有多个组件同时存在,那么请求量会瞬间爆炸
并且在请求接口时可能会出现闪烁或加载不及时的情况,体验上也是更差一筹
未知节点
场景:我选中了部门 2,因为是懒加载的,不知道下方有到底多少人,这时候我通过搜索部门 2下方的子员工人员这时候显示的是这样的:

假如我取消子员工 2-2 的选中,那么此时我选中的应该是哪些值呢
正确的显示应该是 子员工 2-1,子部门 2-1 …… 等等
当然这里也可以通过接口,在取消选中的时候,再次获取数据,但是实在费力
接口集中获取
回到最初的想法:假如数据可以一次性获取, 那么数据的选择,搜索通过前端自己就能完成,并且初始值的显示也会非常顺利,不过这里就需要后端的一些支持。
结论
- 懒加载:
- 优势:适合大数据量场景,能减少初始加载时间与资源消耗,支持动态数据更新 ,有较好灵活性与扩展性。
 - 劣势:用户操作可能有延迟感,初始值与搜索处理复杂,开发需管理更多异步逻辑。
 
 - 一开始请求所有数据:
- 优势:开发简单,数据一致性好,操作即时响应无延迟。
 - 劣势:数据量大时初始加载慢,浪费资源,数据更新困难,可扩展性差。
 
 
综上所述,没有绝对更好的方案,应根据具体的业务场景和需求来选择。

                
            
        
浙公网安备 33010602011771号