MST

星途 面试题库

面试题:React中长列表虚拟化技术的基本原理

请简述React长列表虚拟化技术实现的基本原理,包括如何只渲染可见区域的列表项以及如何处理滚动事件来更新渲染的列表部分。
27.2万 热度难度
前端开发React

知识考点

AI 面试

面试题答案

一键面试

基本原理

  1. 只渲染可见区域列表项
    • 计算可见范围:通过获取视口高度、列表项高度以及当前滚动位置,确定哪些列表项在视口内是可见的。例如,假设视口高度为viewportHeight,列表项高度为itemHeight,当前滚动位置为scrollTop,则可见列表项的起始索引startIndex和结束索引endIndex可以通过Math.floor(scrollTop / itemHeight)Math.min(Math.floor((scrollTop + viewportHeight) / itemHeight), totalItems)计算得出(totalItems为列表项总数)。
    • 虚拟列表渲染:只渲染startIndexendIndex之间的列表项,而不是渲染整个长列表。在React中,可以通过过滤数据数组,只传递可见范围内的数据给渲染组件。例如:
const visibleItems = data.slice(startIndex, endIndex);
return (
  <div>
    {visibleItems.map((item, index) => (
      <div key={index}>{item}</div>
    ))}
  </div>
);
  1. 处理滚动事件更新渲染列表部分
    • 绑定滚动事件:在React组件中,可以使用useEffect钩子在组件挂载时绑定滚动事件,在组件卸载时解绑滚动事件。例如:
import { useEffect } from'react';
useEffect(() => {
  const handleScroll = () => {
    // 处理滚动逻辑
  };
  window.addEventListener('scroll', handleScroll);
  return () => {
    window.removeEventListener('scroll', handleScroll);
  };
}, []);
  • 更新可见范围:在滚动事件处理函数中,重新计算当前滚动位置对应的可见列表项范围。通过window.pageYOffset获取当前滚动位置,然后按照上述计算可见范围的方法重新计算startIndexendIndex
  • 触发重新渲染:一旦可见范围更新,通过设置状态(例如setStartIndexsetEndIndex)来触发React组件的重新渲染,从而更新渲染的列表部分,显示新的可见列表项。例如:
import { useEffect, useState } from'react';
const MyList = () => {
  const [startIndex, setStartIndex] = useState(0);
  const [endIndex, setEndIndex] = useState(10);
  useEffect(() => {
    const handleScroll = () => {
      const scrollTop = window.pageYOffset;
      const newStartIndex = Math.floor(scrollTop / itemHeight);
      const newEndIndex = Math.min(Math.floor((scrollTop + viewportHeight) / itemHeight), totalItems);
      setStartIndex(newStartIndex);
      setEndIndex(newEndIndex);
    };
    window.addEventListener('scroll', handleScroll);
    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, []);
  const visibleItems = data.slice(startIndex, endIndex);
  return (
    <div>
      {visibleItems.map((item, index) => (
        <div key={index}>{item}</div>
      ))}
    </div>
  );
};