使用React处理数据相对来说比较容易,因为React的设计就是把数据当作状态。但是当你需要处理的数据量很大的时候,麻烦就来了。比如你要处理一个包含500-1000条记录的数据集,这会产生巨大的计算量并导致性能问题。下面我们将学习如何使用虚拟列表来“看起来”渲染了一个长列表。
我们将使用React Virtualized组件来实现我们的需求。它让我们可以以很小的代价渲染大集合数据。
设置
React Virtualized官方已经有很详细的介绍了,可以去它们的github去看看。
我们需要大量的数据,下面我们就来造一些。
1 | function createRecord(count) { |
下面,我们设置一个数字来创造我们需要的数据:
const records = createRecord(1000);
好了,现在我们有需要渲染的数据了。
创建一个虚拟列表
这里是我们创建的一个列表,我们引入使用了库提供的一些展示样式,本篇post不讨论这个。
现在开始感受一下这个demo,速度超级快,是不是?
你可能想知道这背后到底发生了什么,结果发现是一系列很疯狂和酷的sizing、positioning、transform和transitions,是这些技术让一条条记录进入/离开可视区。数据都在那里并渲染了,React Virtualized创建了一个window,当用户scroll的时候,一条条记录将滑入/出我们的视野。
为了渲染虚拟列表,我们需要List
组件,它内部渲染了一个Grid
组件。
首先,我们从设置rowRenderer
,开始,它是负责渲染单挑数据的组件。
1 | rowRenderer = ({ index, isScrolling, key, style }) => { |
它返回一个包含两个div
的div,里面的两个
div分别是
username和
email`。可以看出,这是一个简单的展示用户信息的列表。
rowRenderer
接受几个参数,下面是这些参数的细节:
index
: 记录的数值IDisScrolling
: 代表List
组件是否发生scrollingisVisible
: 代表这条数据是否在可视区内key
: 这条记录在数组中的位置parent
: 定义这个列表是否是另一个列表的parent/childstyle
: 定位这条数据的style对象
下面我们再深入了解一些rowRenderer
函数,我们把它放到List
组件中:
1 | <List |
你可能注意到这里的几个参数:
rowCount
: 接收代表列表长度的数字width
: 列表的宽度height
: 列表的高度rowHeight
: 每条数据的高度rowRenderer
: 用来渲染每条数据的模板,我们将传入之前定义的rowRenderer
函数overscanRowCount
:
用来渲染用户scroll方向额外的数据,防止用户滑动太快,虚拟内容来不及渲染。
最后,代码应该是这样的:
1 | const { List } = ReactVirtualized |
Cell measure
文档里介绍,cell
measure是一个高阶组件,用来暂时渲染列表。现在我们还看不到它,但数据已经在里面被处理并准备好展示了。
什么时候我们需要关心cell measure?最常见的use
case是当我们需要动态计算rowHeight
的时候。React
Virtualized在渲染每一行的时候,会缓存它们的高度值,这样当数据滑出可视区的时候我们也不用再计算它的高度——不管里面的内容是什么,高度都是对的。
首先,我们创建自己的缓存cache
,在我们组件的constructor
里用CellMeasureCache
:
1 | constructor() { |
当我们设置List
组件的时候,把cache
带上:
1 | <List |
传给deferredMeasurementCache
的值会被用来暂时渲染数据,接着——当rowHeight
的计算结果出来的时候——额外的行会流入,就像它们一直在那里。
接着我们将在rowRenderer
函数里使用CellMeasure
替换我们之前的div
:
1 | rowRenderer = ({ index, parent, key, style }) => { |
现在数据已经被获取、缓存并准备好展示在虚拟window里了!
虚拟table
虽然本片post主要说列表,但万一当我们需要渲染table怎么办?React
Virtualized也帮我们做了这件事情。这时我们需要使用Table
和Column
组件。
下面是代码:
1 | class App extends React.Component { |
这个Table
组件包括下面的参数:
width
height
headerHeight
rowHeight
rowCount
rowGetter
: 返回这行的数据
如果看一下Column
组件,你会发现我们设置了一个dataKey
参数。它是每条数据拥有的独一无二的id。
总结
希望这篇post可以帮你了解React
Virtualized可以做哪些事情,它如何让列表渲染变得很快,并如何在项目中使用它。
我们只讨论了皮毛,这个库覆盖了更多的use case,如在scroll的时候为记录generate
placeholders、实时获取/缓存数据的无限加载组件等等。
它将给你很多可以play with的东西!
此外,这个包维护的很好,实际上你可以加入Slack group来跟踪这个项目,贡献它,和其他folks取得联系。
还有一条值得注意的是,React Virtualized在StackOverflow上有它自己的标签,这是一个寻找问题的答案的地方,也可以po出你的问题。