一、前言
本方案肯定不是最佳实践,从产品层面到代码层面都有优化的空间。因为当时在需求评审时,pm并没有明确该页面的需要承载的数据量级,以至于在提测之后才知道该页面需要承载的压力之大,所以各方均没有时间再做大量的改造,只能从现有的代码上尽力做下优化。
二、功能介绍
一个嵌套了多个子层级,每一个层级均具有动态增、删、上移、下移、复制功能的form表单,且该表单也支持回显编辑再提交。页面结构大致可以分为两大部分:
1、配置页面头部:
2、模块设置(核心组件):
(1)pc端模块设置和移动端模块设置内部用的是同一个组件,所以只拿单个模块设置说明。
(2)在pc端模块设置内部,点击【+新增模块】可以无限增加多个模块;点击模块上方的编辑或模块本身可以将模块展开。
(3)在单个模块内部右侧有一个【继续添加元素】按钮,点击后向模块内部添加子元素。
(4)在元素块内部,通过切换元素类型,会展示相应的组件。
(5)选择元素类型为明细,则展示如下组件,点击【+】则可添加多条列表数据
三、代码结构及后续优化:
最初的结构构思,(因为前置条件,所以把这个需求当成是一个普通的Form表单去对待,也没有好好做下设计)我是将页面拆分成3个form组件:分别为头部、pc模块设置、移动模块设置。
测试中发现这种结构的代码在大数据量回显(3000个form.item元素)的时候,页面直接就加载不出来崩掉了。但上线后实际配置的数据量大约在7000个元素节点,也就是说当前代码根本不满足业务要求。
所以我做了第一次优化:拆!(如下图)
头部不变,主要拆解大模块的form结构,从原本将所有子模块放在一个form中,变成每一个子模块都是一个form。拆解后页面可以可以正常渲染出来了,但随之又发现了一个新的问题:当一个子模块内部的元素较多的时候,如果用户修改某一个元素的值,渲染速度是非常慢的(比如我在一个input框中输入‘你好世界’,要等20s左右才会渲染到页面上)。这是由于在antd3中:当修改一个表单项的值时,整个表单组件会重新渲染,并且会触发整个表单的重新渲染。
所以我又做了进一步优化:继续拆!(如下图)
拆成以元素块为一个form表单。此时页面的性能除首次加载比较慢之外(因为要渲染全量数据所以比较慢),在做一些增删改的操作时,完全没有任何问题。
看到这可能小伙伴们会有疑问:为什么不能分模块加载,为什么不能展开哪个模块再对哪个模块做相应的加载,或者借助于例如react-virtualized库去可见区域渲染。原因还是因为开发到这已经是在测试阶段了,无论采用哪种方案,前端和后端的代码结构都有着十分大的改动,所以只能亡羊补牢。而且当前的页面设计是:数据是存在各个子form表单中的,点击保存按钮遍历所有form表单,通过 getFieldsValue() 取到所有的值再进行聚合。如果不将全部数据首次渲染出来,当点击保存时,就会导致未被渲染的数据丢失。
四、关键代码实现
1、数据处理的逻辑
首先我是给每一个元素绑定了一个唯一id,在点击保存的时候,所有的数据都是平铺在一个对象内,如下图所示:
可以看到,每一个模块最上方的模块名称和备注的key名是由:`${模块Id}_${元素名称}`拼成的;而元素的key名则是由:`${模块Id}_${元素I