使用React-Window实现虚拟滚动效果的示例代码
作者:慕仲卿
1. 了解 React-Window
React-Window 是一个为 React 应用程序中高效渲染大数据集而设计的库。它基于窗口化或虚拟化的原则运行,这对于提高数据量大的 Web 应用程序的性能至关重要。
2. React-Window 原理
- 窗口化: React-Window 仅渲染用户可视区域中当前可见的元素。这最小化了 DOM 元素的数量,减少内存使用并提升性能。
 - DOM 元素的可重用性: 用户滚动时,React-Window 重用现有的 DOM 元素来展示新项,进一步提升性能。
 - 简化的 API: 相比于 React-Virtualized,它提供了更简单、更流畅的 API,使用起来更容易,同时功能强大。
 
3. 安装
通过 npm 安装 React-Window:
npm install react-window
4. 基本使用
一个基本的列表实现:
import { FixedSizeList as List } from 'react-window';
const MyList = () => (
    <List
        height={150}
        itemCount={1000}
        itemSize={35}
        width={300}
    >
        {({ index, style }) => <div style={style}>Item {index}</div>}
    </List>
);
5. 高级使用案例和示例
5.1 自定义项目渲染器
自定义列表或网格中每个项目的渲染方式。
import { FixedSizeList as List } from 'react-window';
// 偶数和奇数项组件
const EvenItem = ({ index }) => <div>Even: Item {index}</div>;
const OddItem = ({ index }) => <div>Odd: Item {index}</div>;
const MyCustomItem = ({ index, style }) => (
    <div style={style}>
        {index % 2 === 0 ? <EvenItem index={index} /> : <OddItem index={index} />}
    </div>
);
const MyList = () => (
    <List
        height={150}
        itemCount={1000}
        itemSize={35}
        width={300}
    >
        {MyCustomItem}
    </List>
);
5.2 动态加载
结合数据获取实现用户滚动时动态加载和渲染数据。
import { InfiniteLoader, List } from "react-window-infinite-loader";
const loadMoreItems = /* 加载更多项目的函数 */
<InfiniteLoader
    isItemLoaded={/* 检查项目是否加载的函数 */}
    itemCount={1000}
    loadMoreItems={loadMoreItems}
>
    {({ onItemsRendered, ref }) => (
        <List
            onItemsRendered={onItemsRendered}
            ref={ref}
            {/* 其他属性 */}
        >
            {/* 项目渲染器 */}
        </List>
    )}
</InfiniteLoader>
有关此示例的更多详细信息,请查看下一章节。
5.3 性能优化
演示减少渲染 DOM 元素的数量。
// 使用相同的 FixedSizeList 示例,但使用大量数据集
<List
    height={150}
    itemCount={100000}
    itemSize={35}
    width={300}
>
    {({ index, style }) => <div style={style}>Item {index}</div>}
</List>
6. 详细实现动态加载
为了展示如何在使用 Express 构建的后端中与 React-Window 结合实现动态加载,我们创建一个示例,前端从后端获取数据,用户通过列表滚动时请求更多数据。后端将提供分页数据,前端在达到当前加载项的末尾时请求更多数据。
使用 Express 的后端设置
创建一个简单的 Express 服务器:
首先,建立一个能够提供分页数据的 Express 服务器。
 express = require('express');
const app = express();
const cors = require('cors');
const PORT = 3000;
app.use(cors());
// 模拟数据数组
const data = new Array(1000).fill(null).map((_, index) => ({ id: index, name: `Item ${index}` }));
// 获取分页数据的端点
app.get('/data', (req, res) => {
    const { page = 1, limit = 50 } = req.query;
    console.log('req.query:', req.query)
    const startIndex = (page - 1) * limit;
    const endIndex = page * limit;
    res.json({
        data: data.slice(startIndex, endIndex),
        total: data.length
    });
});
app.listen(PORT, () => console.log(`Server running on port ${PORT}`));
在这个设置中,创建了一个模拟数据数组,/data 端点根据请求的页码和限制提供部分数据。
使用 React-Window 和无限加载的前端设置
在前端实现无限加载:
使用 React 和 React-Window 实现无限加载特性。
import React, { useState, useEffect } from 'react';
import { FixedSizeList as List } from 'react-window';
import axios from 'axios';
const ROW_HEIGHT = 35;
function InfiniteLoadingList() {
    const [items, setItems] = useState([]);
    const [total, setTotal] = useState(0);
    const [page, setPage] = useState(1);
    const loadMoreItems = async () => {
        const { data } = await axios.get(`http://localhost:3000/data?page=${page}&limit=50`);
        setItems(prev => [...prev, ...data.data]);
        setTotal(data.total);
        setPage(prev => prev + 1);
    };
    useEffect(() => {
        loadMoreItems();
    }, []);
    useEffect(() => {
        console.log('items', items);
    }, [items]);
    const isItemLoaded = index => index < items.length;
    const renderItem = ({ index, style }) => (
        <div style={style}>
            {isItemLoaded(index) ? items[index].name : 'Loading...'}
        </div>
    );
    return (
        <List
            height={400}
            itemCount={total}
            itemSize={ROW_HEIGHT}
            width={300}
            onItemsRendered={({ visibleStopIndex }) => {
            console.log('visibleStopIndex:', visibleStopIndex)
                if (!isItemLoaded(visibleStopIndex) && items.length < total) {
                    loadMoreItems();
                }
            }}
        >
            {renderItem}
        </List>
    );
}
export default InfiniteLoadingList;
在这个 React 组件中,使用 useState 和 useEffect 管理列表的状态,并在用户滚动到已加载项目末尾附近时获取新数据。FixedSizeList 的 onItemsRendered 函数检查是否需要加载新数据。
总结
这个设置展示了在 React 应用程序中使用 React-Window 实现基本的动态加载和使用 Express 后端提供分页数据的简单实现。它有效地展示了如何通过根据需要逐步加载数据来处理大型数据集,改善性能和用户体验。
7. 结论
React-Window 对于解决 React 应用程序中渲染大型数据集相关的性能问题起着关键作用。它对虚拟化的方法,结合简化的 API,使其成为开发者的首选。通过仅渲染可见内容并高效地重用 DOM 元素,React-Window 确保即使在数据量庞大的情况下,应用程序也能保持响应性和性能。
到此这篇关于使用React-Window实现虚拟滚动效果的示例代码的文章就介绍到这了,更多相关React虚拟滚动内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
