likes
comments
collection
share

一行代码解决Taro中VirtualList虚拟列表渲染抖动的问题

作者站长头像
站长
· 阅读数 17

引言:问题背景

使用Taro 提供的组件库 VirtualList 时,数据源长度改变后,发生渲染抖动。

需求的普遍场景是上百条甚至上千条数据,因此我们采用了虚拟列表。然而,也有例外情况,即虚拟列表的数据源长度变为了个位数,比如原来是 8 条,改变筛选条件后,结果为 5 条数据,此时出现了渲染抖动。

现象: 改变筛选条件后,列表由原来的 8 条从下到上 缓慢 减为了 5 条,下面的数据逐渐消失而不是直接消失(消失动态数据,如state——>留下静态数据——>全部消失),存在一个渲染抖动的过程。

这种情况在数据量大时未发现。

那么本篇内容就对解决渲染抖动的过程进行记录和分享,希望可以帮助到你。

一、虚拟列表的使用场景

首先,我们来熟悉一下使用虚拟列表(Virtual List)的场景。它是一种优化长列表性能的技术,适用于以下场景:

  1. 长列表:当列表中的项非常多时,例如几百甚至几千个,虚拟列表可以提高性能并减少内存占用。
  2. 可滚动列表:当列表需要支持滚动时,虚拟列表可以提供平滑的滚动体验,无论列表有多长。
  3. 复杂列表项:当列表项比较复杂,包含大量的子组件、图片或其他复杂的渲染逻辑时,虚拟列表可以减少不必要的渲染开销。

其次,我们再来了解一下它的其他知识:

  • 虚拟列表的工作原理是只渲染当前可见区域内的列表项,而不是一次性渲染所有的列表项。通过动态加载和卸载列表项,虚拟列表可以显著提高性能和响应速度。
  • 在使用虚拟列表时,需要指定列表的高度(或宽度)和每个列表项的高度(或宽度)。虚拟列表会根据可见区域的大小和滚动位置计算出当前需要渲染的列表项,并在滚动时动态更新渲染的内容。
  • 虚拟列表通常与滚动容器(如ScrollView)结合使用,以实现滚动功能。它可以在Web开发中使用,也可以在跨平台开发框架(如Taro、React Native等)中使用。
  • 虚拟列表的数据常来源于远程加载。

总之,虚拟列表就是只渲染当前可视区域(visible viewport) 的视图,非可视区域的视图在用户滚动到可视区域再渲染:

一行代码解决Taro中VirtualList虚拟列表渲染抖动的问题

二、解决Taro组件VirtualList的抖动问题

1. VirtualList的使用方法

项目中,如果我们引用了Taro,那么正常是这样写的:

// ...
import VirtualList from "@tarojs/components/virtual-list";

export default class Index extends Component {
  state = {
    data: [],
  }
  function buildData() {
    // 接口请求列表数据
  }
  // 列表单项组件
  const Row = React.memo(({ id, index, data }) => {
    // odd 奇数,even:偶数
    return (
      <View id={id} className={index % 2 ? 'ListItemOdd' : 'ListItemEven'}>
        Row {index} : {data[index]}
      </View>
    )
  })

  render() {
    const { data } = this.state;
    const dataLen = data.length;
    return (
      <VirtualList
        height={800} /* 列表的高度 */
        width="100%" /* 列表的宽度 */
        item={Row} /* 列表单项组件这里只能传入一个组件 */
        itemData={data} /* 渲染列表的数据 */
        itemCount={dataLen} /* 渲染列表的长度 */
        itemSize={100} /* 列表单项的高度  */
      />
    )
  }
}

部分参数说明:

item: ReactComponent (原 children 参数) 将要渲染的列表单项组件。组件的 props 有 4 个属性:

  • id: 单项的 ID,必须传入组件的 id 中
  • index: 组件渲染数据的索引
  • data: 组件渲染的数据,同虚拟列表 itemData
  • isScrolling: 组件是否正在滚动,当 useIsScrolling 值为 true 时返回布尔值,否则返回 undefined

推荐使用 React.memo 或 React.PureComponent 或使用 shouldComponentUpdate() 来优化此组件,避免不必要的渲染。

上述代码参考 Taro官方文档,博主有二次编辑、加注释,方便更好的理解。

2. 解决之法

若是参考官方文档,它并未提到 key。 熟悉React的同学会知道,key 是一个 ReactElement 的基本属性,它的作用是保证组件的唯一性,提高渲染性能(这一点如果不清楚的话评论区可以提问)。

常见案例:如果在数组 map 中,我们经常会给渲染组件加一个key。

那么,博主也是又看官网的,又搜百度的,没找到答案。后面在openAI的提示下,才有了加key的方案,它是这么说的:

  • 可能是因为Taro的VirtualList组件在数据源长度变化时,没有立即更新渲染的列表项,而是在下一次渲染时才更新,这就导致了抖动的问题。
  • 为了解决这个问题,你可以尝试在数据源长度变化时,强制VirtualList组件立即重新渲染。你可以通过在VirtualList组件的key属性上设置一个与数据源长度相关的值来实现这个目标。当数据源长度变化时,key属性的值也会变化,这会导致VirtualList组件立即重新渲染。

修改原代码:

<VirtualList
   key={data.length} // 添加这一行
   height={800} /* 列表的高度 */
   width="100%" /* 列表的宽度 */
   item={Row} /* 列表单项组件,这里只能传入一个组件 */
   itemData={data} /* 渲染列表的数据 */
   itemCount={dataLen} /* 渲染列表的长度 */
   itemSize={100} /* 列表单项的高度  */
/>

核心即加 key,一行代码解决: key={data.length} ,再次运行项目就没有之前的问题啦!

三、扩展场景:关于key的其他抖动问题,如表格组件

我们在开发项目时,特别是后台管理系统中,表格组件Table使用的格外广泛。 比如 ant design组件库,

import React from 'react'; 
// ...
// render中
<Table columns={columns} pagination={pagination} dataSource={data} />

有时可能遇到表格渲染抖动或错误的现象。例如:更改筛选条件/切换页面,表格会带出先前的行记录;或行记录重复。遇到这些问题,我们首先会去看服务端接口返回是否正常,一看:“接口返回没问题啊!这咋回事啊???”,然后又去看自己的前端代码……

之前博主遇到的时候,心里也是大大的问号,各处排查,最后发现是 rowKey 不唯一导致的渲染出错

解决:Table加个属性:rowKey='recordId'rowKey={(record)=>record.id} ,OK,刷新项目,乱象消失。

关于rowKey的说明:

rowKey表格行 key 的取值,可以是字符串或一个函数string 或function(record): string

Antd官方是这么说的: 按照 React 的规范,所有的数组组件必须绑定 key。在 Table 中,dataSource 和 columns 里的数据值都需要指定 key 值。对于 dataSource 默认将每列数据的 key 属性作为唯一的标识。

点开看大图:

一行代码解决Taro中VirtualList虚拟列表渲染抖动的问题 无论是哪个组件库或框架,VUE也好,React 也好,数组的 key 是非常必要的!

读完本篇文章,你可以获得:

  • 虚拟列表概念
  • 虚拟列表的使用场景
  • 性能优化策略-key
  • 虚拟列表渲染抖动的问题解决
  • 表格抖动或渲染错误的解决方向

希望能帮助到你,如有收获可点赞收藏哦。 如有疑问请评论区提出,欢迎沟通👏🏻