返回
React Hook & TypeScript打造虚拟滚动组件,轻松实现高效渲染巨量数据!
前端
2023-09-15 01:27:59
手把手教你用React Hook和TypeScript打造虚拟滚动组件
1. 明确目标
虚拟滚动组件的目标是:无论用户如何滚动,浏览器始终只渲染当前视口内的元素,从而提高巨量数据渲染的性能。
2. 理解原理
虚拟滚动组件是通过控制视口的滚动位置来实现的。滚动时,组件只更新当前视口范围内的元素,而其他元素保持隐藏状态。滚动完成后,组件根据新的视口位置更新渲染的元素。
3. 开始动手
1)创建React项目
npx create-react-app virtual-scroll-list --template @typescript
2)安装依赖
npm install react-virtualized
3)创建组件
// VirtualScroll.tsx
import React, { useRef, useState } from "react";
import { useVirtual } from "react-virtualized";
interface Props {
data: any[];
renderItem: (item: any) => JSX.Element;
}
const VirtualScroll = ({ data, renderItem }: Props) => {
const scrollRef = useRef<HTMLDivElement>(null);
const [scrollTop, setScrollTop] = useState(0);
const { size, start, end } = useVirtual({
size: data.length,
overscanCount: 20,
onScrollToIndex: setScrollTop,
scrollToIndex: scrollTop,
});
return (
<div ref={scrollRef}>
{data.slice(start, end).map(renderItem)}
</div>
);
};
export default VirtualScroll;
4)使用组件
// App.tsx
import React from "react";
import VirtualScroll from "./VirtualScroll";
const data = new Array(1000).fill(0).map((_, i) => i);
const App = () => {
const renderItem = ({ index }) => (
<div key={index} style={{ height: "50px" }}>
Item {index}
</div>
);
return (
<div style={{ height: "500px", overflow: "auto" }}>
<VirtualScroll data={data} renderItem={renderItem} />
</div>
);
};
export default App;
4. 总结提升
1)优化性能
// VirtualScroll.tsx
const VirtualScroll = ({ data, renderItem }: Props) => {
const scrollRef = useRef<HTMLDivElement>(null);
const [scrollTop, setScrollTop] = useState(0);
const { size, start, end } = useVirtual({
size: data.length,
overscanCount: 20,
onScrollToIndex: setScrollTop,
scrollToIndex: scrollTop,
getScrollTop: () => scrollRef.current?.scrollTop ?? 0,
setScrollTop: (scrollToIndex) => {
if (scrollRef.current) {
scrollRef.current.scrollTo({
top: scrollToIndex,
behavior: "smooth",
});
}
},
});
return (
<div ref={scrollRef}>
<div style={{ height: size * 50 }}>
{data.slice(start, end).map(renderItem)}
</div>
</div>
);
};
2)支持自定义样式
// VirtualScroll.tsx
const VirtualScroll = ({ data, renderItem, itemHeight }: Props) => {
const scrollRef = useRef<HTMLDivElement>(null);
const [scrollTop, setScrollTop] = useState(0);
const { size, start, end } = useVirtual({
size: data.length,
overscanCount: 20,
onScrollToIndex: setScrollTop,
scrollToIndex: scrollTop,
getScrollTop: () => scrollRef.current?.scrollTop ?? 0,
setScrollTop: (scrollToIndex) => {
if (scrollRef.current) {
scrollRef.current.scrollTo({
top: scrollToIndex,
behavior: "smooth",
});
}
},
});
return (
<div ref={scrollRef}>
<div style={{ height: size * itemHeight }}>
{data.slice(start, end).map(renderItem)}
</div>
</div>
);
};
通过以上步骤,我们成功实现了一个虚拟滚动组件,可以轻松应对巨量数据的渲染需求。