react-virtualized 的用法详解
简介
在开发向下滑动列表模块时,我们一般会在元素滚动到底部时,加载新的数据,往后增加dom。然后循环这个过程。一旦数据量很大,因为页面渲染了很多的 dom,这个页面就会很卡顿。接下来就是老板让优化渲染性能。。。
聪明的你马上想到,我们能看到的数据只有外层div这么高一个高度,但是却渲染了海量的数据,那么可以只渲染可视区域的数据,不可见的直接删除掉不就行了。
但是,马上问题就来了,如果要这么实现,怎么保证删除元素之后,当前元素的位置不变,在什么位置删,会不会删多了导致滑动过程中页面展示白屏等等一系列问题。想想都有些头大,这时,react-virtualized 就是其中一个很好的解决方案。
react-virtualized 的 dom 结构
如图所示,react-virtualized 在实现无线滚动时,做了如下操作
创建一个相对定位 (relative)的盒子
列表元素设计为绝对定位(absolute),它的 top 位置相对于盒子顶部,这样,元素位置不会因为其他兄弟节点而变化
滚动过程总,根据可是区域的变化,删除或者增加节点
整个过程就是这样,只是内部的计算,位置处理比较繁琐。下面我们讲一下其组件的一些用法
核心组件
AutoSizer
先看用法
import AutoSizer from 'react-virtualized/dist/es/AutoSizer';
<AutoSizer>
{({ height, width }) => {
return <div style={{height, width}} />
}
</AutoSizer>AutoSizer 组件很简单,核心就是获取可视壳子的宽高,如果把这个组件包裹在外层,它能给内部提供一个真的宽高,方便内部组件调用。
对一些不确定宽高的组件比较适用,如果可视窗口比较稳定,也可以不用。
InfiniteLoader
通过名字可以大概知道意思,无限加载,这个组件给我们提供一个滚到到底部触发加载的时机,这样,我们不用计算,考虑什么时候元素滚动到最底部,要请求接口的时机。
示例如下
<InfiniteLoader
isRowLoaded={({index}) => boolean}
loadMoreRows={() = >{...}}
rowCount={15}
threshold={3}
>
...
</InfiniteLoader>这个组件有四个核心属性
| 属性 | 类型 | 说明 |
|---|---|---|
| isRowLoaded | Function | 计算当前行是否已经加载了 |
| loadMoreRows | Function | 加载更多数据的函数 |
| rowCount | Number | 一共的数据行数 |
| threshold | Number | 提前多少行,开始请求数据,默认15行 |
List
List 则是提供一个列表的渲染组件
先看用法
import React from 'react';
import ReactDOM from 'react-dom';
import {List} from 'react-virtualized';
// List data as an array of strings
const list = [
'Brian Vaughn',
// And so on...
];
function rowRenderer({
key, // Unique key within array of rows
index, // Index of row within collection
isScrolling, // The List is currently being scrolled
isVisible, // This row is visible within the List (eg it is not an overscanned row)
style, // Style object to be applied to row (to position it)
}) {
return (
<div key={key} style={style}>
{list[index]}
</div>
);
}
// Render your list
ReactDOM.render(
<List
width={300}
height={300}
rowCount={list.length}
rowHeight={20}
rowRenderer={rowRenderer}
/>,
document.getElementById('example'),
);List 几个必传的属性如下
| 属性 | 类型 | 说明 |
|---|---|---|
| width | Number | 可是区域的宽 |
| height | Number | 可是区域的高度 |
| RowCount | Number Function | 总行数,可以是固定值,也可以通过函数计算得到,返回一个数字 |
| Rowheight | Number Function | 每一行的高度,可以是固定值,也可以通过函数计算得到,返回一个数字 |
| rowRenderer | Function | 每一行的渲染函数 |
其中 RowCount 和 Rowheight 可以设置为固定值,亦可以用函数动态计算
rowRenderer 则是一个渲染函数,需要注意两点
key 设置为 index
必须传入 style,这个 style 是动态计算出来的,为设定好元素的height 和 top值,不设置 style,则元素的位置不对。
<div key={key} style={style}>
{list[index]}
</div>这里,key 和 style 必传
总结
我们来总结一下,实现一个无限滚动需要的内容
通过三个组件的配置,最终实现整个无限滚动需求。看起来整个过程还是比较繁琐的,需要理解一些原理,以及很多组件的使用方法。
但是,如果把所有内容放在一起,对与开发者的心理成本可能又会上一个台阶,通过这样分部拆解,希望可以好理解一点。
最后,我们在写一个完整的例子
import AutoSizer from 'react-virtualized/dist/es/AutoSizer';
import List from 'react-virtualized/dist/es/List';
import InfiniteLoader from 'react-virtualized/dist/es/InfiniteLoader';
function Demo() {
const [list, setList] = useState([])
// 加载下一组数据的函数
const loadMoreRows = () => {
setTimeout(() => {
setList([...list, ..[2, 4, 5]])
}, 200)
}
// 加载组件,元素是否加载
const isRowLoaded = ({index}) => {
return index < list.length
}
// 渲染 list 的但组件渲染函数
const rowRenderer = ({index, style}) => {
return (
<div key={key} style={style}>
{list[index]}
</div>
)
}
return (
<AutoSizer>
{({ height, width }) => {
return return (
<InfiniteLoader
isRowLoaded={isRowLoaded}
loadMoreRows={loadMoreRows}
rowCount={list.length}
threshold={2}
>
<List
width={width}
height={height}
rowCount={list.length}
rowHeight={20}
rowRenderer={rowRenderer}
/>
</InfiniteLoader>
}
</AutoSizer>
)
}
原文地址:https://webfem.com/post/react-virtualized,转载请注明出处