用react-window优化长列表性能的实战经验分享
先看效果,再看代码
最近在做一个项目,里面有个需求是展示一个超长的列表,几千条数据那种。直接用普通的 <ul> 渲染?开玩笑,页面直接卡死。于是我翻出了 react-window,亲测有效,性能杠杠的。
简单来说,react-window 是一个用于渲染大型列表的 React 库,它通过只渲染可见区域的内容来提升性能。废话不多说,先上代码:
import React from 'react';
import { FixedSizeList as List } from 'react-window';
const Row = ({ index, style }) => (
<div style={style}>Row {index}</div>
);
const App = () => (
<List
height={500}
itemCount={1000}
itemSize={35}
width={300}
>
{Row}
</List>
);
export default App;
这段代码的效果是一个高度为 500px、宽度为 300px 的容器,里面有 1000 条数据,但只会渲染当前可见区域的几条。运行一下,你会发现滚动非常流畅,内存占用也很低。
这个场景最好用
我遇到过一个实际场景:后台管理系统需要展示用户的日志记录,数据量动辄上万条。如果用传统的 map 遍历渲染,别说用户体验了,开发者自己看着都难受。
react-window 在这种场景下简直完美。尤其是固定高度的列表,比如日志记录、订单列表、聊天记录等。代码稍微改改就能用:
import React from 'react';
import { FixedSizeList as List } from 'react-window';
const LogItem = ({ index, style }) => (
<div style={{ ...style, padding: '10px', borderBottom: '1px solid #ccc' }}>
Log Entry {index + 1}: Some log content here
</div>
);
const LogViewer = () => (
<List
height={600}
itemCount={10000}
itemSize={50}
width={'100%'}
>
{LogItem}
</List>
);
export default LogViewer;
这里我把 width 设置为 '100%',让列表自适应父容器宽度。亲测有效,尤其适合那种全屏展示的后台界面。
踩坑提醒:这三点一定注意
虽然 react-window 很好用,但也有一些坑点需要注意:
- 动态高度的坑:如果你的列表项高度不固定,那就不能用
FixedSizeList,而是要用VariableSizeList。但是,动态高度的性能会差一些,建议尽量避免。 - 样式问题:列表项的样式需要手动设置,比如
padding和border,否则可能会出现对齐问题。我在一个项目里折腾了半天才发现是因为没加box-sizing: border-box;。 - 滚动事件失效:如果在列表外面套了一个自定义滚动容器,记得给
List组件传递正确的scrollOffset或者监听滚动事件,否则滚动可能会失效。
举个例子,动态高度的实现方式如下:
import React from 'react';
import { VariableSizeList as List } from 'react-window';
const getItemSize = (index) => (index % 2 === 0 ? 50 : 100);
const Row = ({ index, style }) => (
<div style={style}>Row {index} with dynamic height</div>
);
const App = () => {
const listRef = React.useRef(null);
return (
<List
height={500}
itemCount={1000}
itemSize={(index) => getItemSize(index)}
width={300}
ref={listRef}
>
{Row}
</List>
);
};
export default App;
这里通过 itemSize 函数动态计算每一行的高度,虽然灵活,但性能确实不如固定高度。
高级技巧:嵌套滚动和自定义内容
有时候我们需要在一个页面中嵌套多个滚动区域,或者在列表项中加入复杂的自定义内容,比如图片、按钮、甚至是图表。
这里分享一个我用过的高级技巧:嵌套滚动。假设我们有一个左右布局的页面,左边是一个固定高度的导航栏,右边是一个可滚动的列表:
“javascript
import React from 'react';
import { FixedSizeList as List } from 'react-window';
const Sidebar = () => (
<div style={{ width: 200, backgroundColor: '#f0f0f0', padding: '10px' }}>
Sidebar Content
</div>
);
const Row = ({ index, style }) => (
<div style={style}>
<img
src={https://jztheme.com/images/sample-${index % 10}.jpg}Sample ${index}
alt={}
style={{ width: '100%', height: 'auto' }}
/>
<p>Row {index}</p>
</div>
);
const App = () => (
<div style={{ display: 'flex', height: '100vh' }}>
<Sidebar />
<div style={{ flex: 1, overflow: 'hidden' }}>
<List
height={window.innerHeight}
itemCount={1000}
itemSize={200}
width={'100%'}
>
{Row}
</List>
</div>
</div>
);
export default App;
`>
这里我把 List 的高度设置为 window.innerHeight,让它填满右侧区域。每个列表项包含一张图片和一段文字,滚动依然很流畅。
拓展用法:更多可能性
react-window 还有很多拓展用法,比如结合虚拟化表格、无限滚动加载、甚至是动画效果。这些功能我还在摸索中,后续会继续分享。
以上是我个人对 react-window 的完整讲解,有更优的实现方式欢迎评论区交流。这个技巧的拓展用法还有很多,后续会继续分享这类博客。

暂无评论