当前位置:首页 > React

react实现虚拟列表

2026-01-26 22:14:40React

虚拟列表的概念

虚拟列表是一种优化长列表渲染性能的技术,通过仅渲染可视区域内的列表项,减少DOM节点数量和内存占用。适用于需要展示大量数据的场景,如聊天记录、表格数据等。

实现虚拟列表的关键步骤

计算可视区域高度和滚动位置 获取容器元素的高度和当前的滚动位置,确定需要渲染的列表项范围。使用useRefuseEffect监听滚动事件。

const containerRef = useRef(null);
const [scrollTop, setScrollTop] = useState(0);

useEffect(() => {
  const handleScroll = () => {
    setScrollTop(containerRef.current.scrollTop);
  };
  containerRef.current.addEventListener('scroll', handleScroll);
  return () => {
    containerRef.current.removeEventListener('scroll', handleScroll);
  };
}, []);

计算可见项的起始和结束索引 根据滚动位置、列表项高度和可视区域高度,计算需要渲染的列表项范围。使用useMemo优化计算性能。

const itemHeight = 50; // 假设每个列表项高度固定
const visibleCount = Math.ceil(containerHeight / itemHeight);
const startIndex = Math.floor(scrollTop / itemHeight);
const endIndex = startIndex + visibleCount;

渲染可见项 根据计算的起始和结束索引,截取对应的数据子集进行渲染。使用绝对定位控制列表项的位置。

const visibleItems = data.slice(startIndex, endIndex).map((item, index) => (
  <div 
    key={item.id}
    style={{
      position: 'absolute',
      top: `${(startIndex + index) * itemHeight}px`,
      height: `${itemHeight}px`,
      width: '100%'
    }}
  >
    {item.content}
  </div>
));

设置容器和占位元素 容器需要设置固定高度和overflow: auto,占位元素用于撑开滚动区域。

<div 
  ref={containerRef}
  style={{ height: '500px', overflow: 'auto' }}
>
  <div style={{ height: `${data.length * itemHeight}px`, position: 'relative' }}>
    {visibleItems}
  </div>
</div>

动态高度虚拟列表的实现

对于高度不固定的列表项,需要预先测量或估算高度,并维护一个位置缓存。

测量实际高度 在列表项渲染后,使用ResizeObservergetBoundingClientRect获取实际高度,并更新位置缓存。

const [positions, setPositions] = useState([]);
const itemRefs = useRef([]);

useEffect(() => {
  const newPositions = [];
  let totalHeight = 0;
  data.forEach((item, index) => {
    const height = itemRefs.current[index]?.getBoundingClientRect().height || estimatedHeight;
    newPositions.push({
      height,
      top: totalHeight,
      bottom: totalHeight + height
    });
    totalHeight += height;
  });
  setPositions(newPositions);
}, [data]);

根据位置缓存计算可见项 使用二分查找快速定位起始和结束索引。

const getStartIndex = (scrollTop) => {
  let low = 0, high = positions.length - 1;
  while (low <= high) {
    const mid = Math.floor((low + high) / 2);
    if (positions[mid].bottom < scrollTop) {
      low = mid + 1;
    } else {
      high = mid - 1;
    }
  }
  return low;
};

性能优化建议

使用React.memo避免不必要的列表项重渲染,对于复杂列表项组件尤其有效。

const MemoizedItem = React.memo(function Item({ item }) {
  return <div>{item.content}</div>;
});

滚动事件使用节流(throttle)或防抖(debounce)减少计算频率,平衡性能与流畅度。

const handleScroll = throttle(() => {
  setScrollTop(containerRef.current.scrollTop);
}, 16);

现有库推荐

对于快速实现,可考虑以下成熟库:

react实现虚拟列表

  • react-window: 提供固定高度和动态高度虚拟列表组件
  • react-virtualized: 功能更全面,支持表格、网格等复杂布局
  • react-virtuoso: 支持动态高度、分组等高级功能

标签: 列表react
分享给朋友:

相关文章

vue列表实现

vue列表实现

Vue 列表实现方法 使用 v-for 指令 v-for 是 Vue 中用于渲染列表的核心指令,基于数据源动态生成 DOM 元素。语法格式为 item in items 或 (item, index)…

react如何记忆

react如何记忆

React 记忆技术 在 React 中,记忆(Memoization)是一种优化技术,用于避免不必要的重新渲染或计算。React 提供了多种内置方法和第三方库来实现记忆功能。 useMemo Ho…

react如何取消渲染

react如何取消渲染

取消渲染的方法 在React中,取消渲染通常指的是在某些条件下阻止组件渲染或中断正在进行的渲染过程。以下是几种常见的方法: 条件渲染 通过条件判断决定是否渲染组件或部分内容。可以使用if语句或三元运…

如何构建react

如何构建react

构建 React 项目的步骤 安装 Node.js 和 npm 确保系统已安装 Node.js(包含 npm)。可通过命令行验证: node -v npm -v 使用 Create React Ap…

react如何引入

react如何引入

引入React的方法 React可以通过多种方式引入项目,具体取决于项目需求和开发环境。以下是常见的几种方法: 通过CDN引入 在HTML文件中直接通过CDN链接引入React和ReactDOM:…

如何设计react组件

如何设计react组件

设计 React 组件的核心原则 React 组件的设计需要遵循高内聚、低耦合的原则,确保组件功能独立且易于维护。组件的设计可以分为展示组件和容器组件两类,展示组件负责 UI 渲染,容器组件负责逻辑处…