vue3之shallowRef以及使用对element-plus table的优化尝试
首先,先大概回顾一下相关概念吧
ref、shallowRef
ref 接受一个内部值,返回一个响应式的、可更改的 ref 对象,此对象只有一个指向其内部值的属性 .value。
如果将一个对象赋值给 ref,那么这个对象将通过 reactive 转为具有深层次响应式的对象。这也意味着如果对象中包含了嵌套的 ref,它们将被深层地解包。
若要避免这种深层次的转换,请使用 shallowRef 来替代。
和 ref() 不同,shallowRef 的内部值将会原样存储和暴露,并且不会被深层递归地转为响应式。只有对 .value 的访问是响应式的。
以上是vue官方解释,也就是说如果存在大量数据定义的时候,如果不需要深层的监听,那么使用 shallowRef 是较好的选择
vue官方也在说虚拟dom的诟病:
element-plus table 中的 ref
前端时间,在公司项目中vue2 升级到 vue3的过程中,发现vue3支持的element-plus table相比 vue2 版本的element 性能下降很多,表格数据量大的时候渲染较慢。
于是乎,带着问题搜了搜,问题初步定位获取跟ref深层次有关系,然后扒拉一下element-plus table的源码看看:
目前都是ref来定义表格数据,考虑到ref和shallowRef的特性,替换为shallowRef,减少响应式数据依赖会不会让表格渲染速度提升来呢,vue官方优化文档中也在说,减少大型不可变数据的响应性开销
带着问题,先去尝试一下。
ref 替换 shallowRef
尝试流程: 1、vite创建vue3项目;2、原UI表格部分,引用element-plus,创建一个页面使用element-plus的table,创建一个10列,200行的表格展示,另外每行添加一下开关切换数据渲染表格,计算渲染时间;3、拷贝 element-plus table 源码到当前项目,在创建一个table页面,引用拷贝的源码部分;4、切换相同的数据交互,记录渲染时间
创建项目、表格页面
vite初始化一个 vue3 项目,引入 element-plus,使用 el-table 实现一个 12列 * 200 行的表格(一个10列200行的表格数据应该也是常见的情况了)。
添加了el-switch控制表格局部数据更新,添加总开关测试整个table渲染时间,代码就不贴了就一个表格加数据循环
简单贴一下JS部分,数据渲染计时:
element-plus table 源码改造
表格data中的 ref 定义替换成 shallowRef ,当前看element-plus的版本是到了2.3.1(我当时用的2.2的版本),打开官方element-plus,下载你本地项目中使用的版本,将 table 目录(element-plus-2.2.x/packages/components/table) copy 到项目中的 src/table 下;
复制一个上面使用原element-plus的table的页面,添加一行el-table的引用,指定到一个新增的 table 组件内,只增加一行代码
import ElTable from "@/table/src/table.vue";
项目启动会报一些错误,都是些引用上的错误,接下类修改一下引用
1、在 table 目录中搜索 @element-plus 相关关键字,并进行批量替换
// @element-plus/directives => element-plus/es/directives/index
// @element-plus/hooks => element-plus/es/hooks/index
// @element-plus/utils => element-plus/es/utils/index
2、搜索 @element-plus/components 改为直接从 ‘element-plus’ 引入
import ElCheckbox from '@element-plus/components/checkbox'
// 替换为
import { ElCheckbox } from 'element-plus'
具体版本可能会存在不同引用问题,依据提示解决一下报错问题,让项目启动起来
3、在 src/table/src/store/watcher.ts 中,将 data 和 columns 数据从 ref 改为 shallowRef
好了,看看效果
渲染时长对比
修改前table数据渲染 | 修改后table数据渲染 |
---|---|
修改前el-switch切换局部数据 | 修改后el-switch切换局部数据 |
---|---|
竟然能减少70%左右的渲染时间,1~2s的时间视觉已经能明显看出来了
加大数据量再测试一下,将行数增加到1000行:
table数据渲染:修改前:15.771s;修改后:4.477s
el-switch局部数据:修改前:5.675s;修改后:2.318s
增加不同数据量来发现,减少的渲染时间大概是在 60%~70%之间,数据量越大渲染时间越久,视觉看到的也就更明显了。
最后
element-plus table 的 ref 替换 shallowRef 后发现表格减少了大概60%~70%的渲染时间,而且数据量越大渲染时间越久,视觉效果也就更明显。
shallowReactive只会响应第一层的数据,大部分的表格数据结构也都能适用,如果遇到表格数据中还有对象的形式,也就是得使用ref的形式了
那么又一个想法来了,那我是不是可以做成属性控制的呢?深层响应、浅层响应,外部属性传值控制就好了,默认内部shallowRef,如有特殊需要就ref