背景

一个消息列表中,有个计时的数据,每秒都会更新。当使用Vue Devtool Flash Updates插件观察组件update时机时,发现不论列表中的某个子项数据是否有变动,都会导致整个列表重新update(下图)。由于update时里面子组件都会重新update,再加上每秒计时导致整个列表的性能收到影响。
image.png

期望是如果有某个子项计时数据变动,那应该只更新某个子项,期望如下图
image.png

排查过程

  • 方向:检查父子组件的传递中是否有其他props导致了变动,逐个排除属性

    • 结果:发现并没有属性能够影响组件本身,只剩列表数组本身,还是会触发
  • 方向:对列表到子项中的各个组件手动做useMemo处理

    • 结果:从内到外都做了缓存,发现几十父组件缓存,其中一个数组元素变动,子组件收到的列表还是会受影响
  • 方向:检查vuex中state getters数据变动,组件内state,getters的异同,看是否会引起不必要的更新

    • Vuex排查结果:vuex的getters中的日期时间数据会引起不必要的刷新,导致即使没有计时显示也会每秒update,改造成变动时再修改vuex state。可以解决问题。
    • Vue排查结果:如果只是组件state里的数组元素的某个属性修改,是局部更新的。但如果是数组中的一个元素被修改,列表还是会整个update

结论

关于 Array<Object> 列表渲染:

  • Vue.$set( state.arr , i , val ) 会触发整个列表组件的update
  • 改为Vue.$set( state.arr[i] , k , val ) 则不会

关于 Vuex 的 getters :

  • getters依赖的getters更新,不像react有useMemo机制,即使基础类型值不变也会触发update
  • getters依赖的state更新,基础类型值不变不会触发update

seasonley
607 声望693 粉丝

一切皆数据