react-virtualized 的用法详解

创建时间.png 2025-12-22
标签.png AI
阅读量.png 17

简介

在开发向下滑动列表模块时,我们一般会在元素滚动到底部时,加载新的数据,往后增加dom。然后循环这个过程。一旦数据量很大,因为页面渲染了很多的 dom,这个页面就会很卡顿。接下来就是老板让优化渲染性能。。。

聪明的你马上想到,我们能看到的数据只有外层div这么高一个高度,但是却渲染了海量的数据,那么可以只渲染可视区域的数据,不可见的直接删除掉不就行了。

但是,马上问题就来了,如果要这么实现,怎么保证删除元素之后,当前元素的位置不变,在什么位置删,会不会删多了导致滑动过程中页面展示白屏等等一系列问题。想想都有些头大,这时,react-virtualized 就是其中一个很好的解决方案。

npm 展示

react-virtualized 的 dom 结构

dom 结构

如图所示,react-virtualized 在实现无线滚动时,做了如下操作

  1. 创建一个相对定位 (relative)的盒子

  2. 列表元素设计为绝对定位(absolute),它的 top 位置相对于盒子顶部,这样,元素位置不会因为其他兄弟节点而变化

  3. 滚动过程总,根据可是区域的变化,删除或者增加节点

整个过程就是这样,只是内部的计算,位置处理比较繁琐。下面我们讲一下其组件的一些用法

核心组件

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 则是一个渲染函数,需要注意两点

  1. key 设置为 index

  2. 必须传入 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,转载请注明出处

webfem 头像
webfem 博客
🧰 最新工具