告别卡顿!react-virtualized无限滚动:InfiniteLoader组件实现数据按需加载

【免费下载链接】react-virtualized React components for efficiently rendering large lists and tabular data 【免费下载链接】react-virtualized 项目地址: https://gitcode.com/gh_mirrors/re/react-virtualized

你还在为长列表渲染导致页面卡顿而烦恼吗?当面对成千上万条数据时,一次性加载不仅浪费带宽,还会严重影响用户体验。本文将介绍如何使用react-virtualized的InfiniteLoader组件实现数据按需加载,让你的应用在处理大量数据时依然保持流畅。读完本文,你将能够:

  • 理解InfiniteLoader的核心原理
  • 掌握InfiniteLoader的基本使用方法
  • 学会处理加载状态和优化加载性能
  • 解决实际应用中可能遇到的常见问题

什么是InfiniteLoader?

InfiniteLoader是react-virtualized库中的一个组件,它能够管理数据的即时加载,当用户向上或向下滚动列表时,按需获取数据。这种方式可以显著提高应用性能,减少初始加载时间,特别适合处理大数据集。

官方文档:docs/InfiniteLoader.md 组件源码:source/InfiniteLoader/InfiniteLoader.js

InfiniteLoader的核心原理

InfiniteLoader的工作原理可以概括为以下几个步骤:

  1. 监听滚动事件:跟踪用户滚动位置,判断是否需要加载更多数据
  2. 检查加载状态:通过isRowLoaded函数判断哪些行需要加载
  3. 批量加载数据:使用loadMoreRows函数批量加载未加载的数据
  4. 更新视图:数据加载完成后,通知列表组件重新渲染

下面是InfiniteLoader的工作流程:

mermaid

基本使用步骤

1. 安装react-virtualized

首先,确保你的项目中已经安装了react-virtualized。如果没有,可以通过npm或yarn安装:

npm install react-virtualized --save
# 或者
yarn add react-virtualized

2. 引入必要的组件

在需要实现无限滚动的组件中,引入InfiniteLoader和List组件:

import { InfiniteLoader, List } from 'react-virtualized';
import 'react-virtualized/styles.css'; // 引入样式文件

3. 实现核心函数

使用InfiniteLoader需要实现两个核心函数:isRowLoadedloadMoreRows

isRowLoaded函数:用于检查指定索引的行是否已经加载

function isRowLoaded({ index }) {
  // loadedRowsMap是一个跟踪行加载状态的对象
  return !!loadedRowsMap[index];
}

loadMoreRows函数:用于加载指定范围内的数据

function loadMoreRows({ startIndex, stopIndex }) {
  // 模拟API请求
  return fetch(`/api/data?start=${startIndex}&end=${stopIndex}`)
    .then(response => response.json())
    .then(data => {
      // 将加载的数据存储起来
      for (let i = startIndex; i <= stopIndex; i++) {
        loadedRowsMap[i] = data[i - startIndex];
      }
    });
}

4. 渲染组件

将List组件作为InfiniteLoader的子组件,并传递必要的属性:

<InfiniteLoader
  isRowLoaded={isRowLoaded}
  loadMoreRows={loadMoreRows}
  rowCount={1000} // 总行数,可以是一个很大的估计值
  minimumBatchSize={10} // 最小加载批次大小
  threshold={15} // 预加载阈值
>
  {({ onRowsRendered, registerChild }) => (
    <List
      ref={registerChild}
      onRowsRendered={onRowsRendered}
      rowCount={1000}
      rowHeight={50}
      rowRenderer={rowRenderer}
      width={300}
      height={500}
    />
  )}
</InfiniteLoader>

5. 实现行渲染函数

最后,实现rowRenderer函数来渲染每一行:

function rowRenderer({ index, key, style }) {
  // 检查行是否正在加载
  if (!isRowLoaded({ index })) {
    return (
      <div key={key} style={style} className="loading-row">
        加载中...
      </div>
    );
  }
  
  // 渲染已加载的行数据
  return (
    <div key={key} style={style}>
      {loadedRowsMap[index]}
    </div>
  );
}

完整的示例代码可以参考:source/InfiniteLoader/InfiniteLoader.example.js

高级配置与优化

跟踪加载状态

在实际应用中,你可能需要更精细地跟踪行的加载状态(例如区分加载中、已加载、加载失败等状态)。可以使用一个对象来存储这些状态:

const STATUS_LOADING = 1;
const STATUS_LOADED = 2;
const STATUS_ERROR = 3;

// 在组件状态中初始化加载状态映射
this.state = {
  loadedRowsMap: {},
  loadingRowCount: 0,
  loadedRowCount: 0
};

// 更新isRowLoaded函数
_isRowLoaded({ index }) {
  const { loadedRowsMap } = this.state;
  // 已加载或加载中的行都视为"已加载",避免重复加载
  return !!loadedRowsMap[index];
}

优化加载性能

  1. 调整批次大小和阈值:根据你的数据特点调整minimumBatchSizethreshold属性,平衡请求次数和预加载量
<InfiniteLoader
  minimumBatchSize={20} // 每次加载20行
  threshold={30} // 当滚动到距离底部30行时开始加载
  // 其他属性...
>
  1. 避免重复请求:使用 memoization 技术避免对同一批数据发起重复请求
// 使用工具函数创建memoizer
import createCallbackMemoizer from '../utils/createCallbackMemoizer';

this._loadMoreRowsMemoizer = createCallbackMemoizer();

// 使用memoizer包装加载函数
this._loadMoreRowsMemoizer({
  callback: () => this._loadUnloadedRanges(unloadedRanges),
  indices: {squashedUnloadedRanges}
});
  1. 错误处理:添加错误处理逻辑,处理数据加载失败的情况
_loadMoreRows({ startIndex, stopIndex }) {
  return fetch(`/api/data?start=${startIndex}&end=${stopIndex}`)
    .then(response => {
      if (!response.ok) throw new Error('加载失败');
      return response.json();
    })
    .then(data => {
      // 处理成功加载的数据
    })
    .catch(error => {
      console.error('数据加载失败:', error);
      // 标记加载错误状态
      for (let i = startIndex; i <= stopIndex; i++) {
        this.setState(prevState => ({
          loadedRowsMap: {
            ...prevState.loadedRowsMap,
            [i]: STATUS_ERROR
          }
        }));
      }
    });
}

常见问题与解决方案

问题1:数据加载后列表没有更新

解决方案:确保在数据加载完成后正确更新状态,并调用列表组件的recomputeRowHeightsforceUpdate方法

// 数据加载完成后通知列表更新
forceUpdateReactVirtualizedComponent(registeredChild, startIndex);

相关源码:source/InfiniteLoader/InfiniteLoader.js#L260

问题2:快速滚动时出现大量加载请求

解决方案:使用resetLoadMoreRowsCache方法重置缓存,在筛选或排序变化时重新加载数据

// 在组件中添加重置方法
resetInfiniteLoader() {
  this.infiniteLoaderRef.resetLoadMoreRowsCache(true);
}

// 在render方法中添加ref
<InfiniteLoader
  ref={ref => this.infiniteLoaderRef = ref}
  // 其他属性...
>

问题3:与Grid组件一起使用

虽然InfiniteLoader通常与List或Table一起使用,但也可以与Grid组件配合。这时需要将Grid的单元格索引转换为行索引:

class MyComponent extends Component {
  constructor(props) {
    super(props);
    this._onSectionRendered = this._onSectionRendered.bind(this);
  }
  
  _onSectionRendered({ columnStartIndex, columnStopIndex, rowStartIndex, rowStopIndex }) {
    const columnCount = columnStopIndex - columnStartIndex + 1;
    const startIndex = rowStartIndex * columnCount + columnStartIndex;
    const stopIndex = rowStopIndex * columnCount + columnStopIndex;
    
    this._onRowsRendered({ startIndex, stopIndex });
  }
  
  render() {
    return (
      <InfiniteLoader {...infiniteLoaderProps}>
        {({ onRowsRendered, registerChild }) => {
          this._onRowsRendered = onRowsRendered;
          return (
            <Grid
              onSectionRendered={this._onSectionRendered}
              ref={registerChild}
              {...gridProps}
            />
          );
        }}
      </InfiniteLoader>
    );
  }
}

更多细节可以参考官方文档中的Grid示例:docs/InfiniteLoader.md#infiniteLoader-and-grid

总结与扩展

通过本文的介绍,你已经了解了如何使用react-virtualized的InfiniteLoader组件实现数据的按需加载。InfiniteLoader可以与List、Table甚至Grid组件配合使用,为你的应用提供流畅的大数据列表体验。

除了InfiniteLoader,react-virtualized还提供了许多其他有用的组件:

要深入了解这些组件,可以查阅官方文档或查看示例代码。希望本文能帮助你构建更高效、更流畅的React应用!

如果你想查看实际运行效果,可以参考项目中的playground示例:playground/

【免费下载链接】react-virtualized React components for efficiently rendering large lists and tabular data 【免费下载链接】react-virtualized 项目地址: https://gitcode.com/gh_mirrors/re/react-virtualized

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐