You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

优化React中4000+对象数组过滤时的性能问题

性能优化方案

针对你处理4000+对象数组时的卡顿问题,核心瓶颈在于大量DOM节点渲染、重复计算和不合理的状态更新,以下是具体优化步骤:

一、用虚拟列表减少DOM渲染(最关键优化)

直接渲染4000+ DOM元素会导致浏览器重绘重排过载,虚拟列表只渲染可视区域内的元素,大幅降低DOM节点数量。

简单虚拟列表实现示例

import { useState, useRef, useEffect } from 'react';

// 抽离虚拟列表组件
const VirtualAirportList = ({ airports }: { airports: Airport[] }) => {
  const [scrollTop, setScrollTop] = useState(0);
  const listRef = useRef<HTMLDivElement>(null);
  const ITEM_HEIGHT = 32; // 匹配你的列表项实际高度

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

  // 计算可视区域的起始/结束索引
  const startIndex = Math.floor(scrollTop / ITEM_HEIGHT);
  const endIndex = Math.min(startIndex + 15, airports.length); // 可视区域固定显示15条,可调整
  const visibleItems = airports.slice(startIndex, endIndex);

  return (
    <div 
      ref={listRef}
      className="airports-list mt-8 search-results-airports h-28 overflow-y-scroll scroll"
      style={{ position: 'relative' }}
    >
      {/* 占位元素,保证滚动条高度正确 */}
      <div style={{ height: `${airports.length * ITEM_HEIGHT}px`, pointerEvents: 'none' }} />
      {/* 可视区域元素容器 */}
      <div 
        style={{ 
          position: 'absolute', 
          top: 0, 
          left: 0, 
          width: '100%',
          transform: `translateY(${startIndex * ITEM_HEIGHT}px)` 
        }}
      >
        {visibleItems.map((airport) => (
          <div key={airport.id} className="flex justify-between" style={{ height: `${ITEM_HEIGHT}px` }}>
            <p className="font-bold text-sm">{airport.country}</p>
            <p className="text-xs">{airport.name}</p>
          </div>
        ))}
      </div>
    </div>
  );
};

二、优化搜索逻辑与状态管理

  1. 预处理缓存搜索字段:提前将所有机场的搜索字段转为小写,避免每次过滤时重复调用toLowerCase()
  2. 分离搜索状态与列表状态:不再直接修改数组状态,而是通过搜索关键词动态计算过滤结果,减少大数组状态更新

修改后的核心逻辑

const { airports } = useContext(MainContext);

// 预处理数据,缓存小写后的字段(仅初始化时执行一次)
const [processedAirports] = useState(() => 
  airports.map(airport => ({
    ...airport,
    nameLower: airport.name.toLowerCase(),
    countryLower: airport.country.toLowerCase(),
    cityLower: airport.city.toLowerCase()
  }))
);
// 仅保存搜索关键词,而非整个过滤后的数组
const [searchKeyword, setSearchKeyword] = useState('');

// 动态计算过滤结果,无需存入状态
const filteredAirports = searchKeyword 
  ? processedAirports.filter(airport => 
      airport.nameLower.includes(searchKeyword) ||
      airport.countryLower.includes(searchKeyword) ||
      airport.cityLower.includes(searchKeyword)
    )
  : processedAirports;

简化输入框事件

删除原来的searchAirports和checkIfEmpty函数,直接绑定关键词更新:

<input
  type="text"
  name="From"
  className="w-full border rounded-xl h-11 p-4 text-sm focus:border-blue-500 outline-none focus:border-2"
  placeholder="Start your flight search"
  value={searchKeyword}
  onChange={(e) => setSearchKeyword(e.target.value.toLowerCase())}
/>

三、移除冗余的状态同步代码

原代码中初始化airportListLocal的useEffect是冗余的,因为useState已经直接用airports初始化,直接删除这段代码:

// 删掉以下冗余代码
useEffect(() => {
  setAirportListLocal(airports);
}, []);

四、用React.memo优化列表项

将列表项抽成独立组件并包裹React.memo,避免无关更新导致的重渲染:

const AirportItem = React.memo(({ airport }: { airport: Airport }) => (
  <div className="flex justify-between">
    <p className="font-bold text-sm">{airport.country}</p>
    <p className="text-xs">{airport.name}</p>
  </div>
));

// 渲染时使用该组件
{visibleItems.map((airport) => (
  <AirportItem key={airport.id} airport={airport} />
))}

五、防抖优化实时搜索(可选)

如果实时输入仍有轻微卡顿,给关键词更新添加防抖,减少过滤计算频率:

const debounce = (fn: Function, delay: number) => {
  let timeoutId: NodeJS.Timeout;
  return (...args: any[]) => {
    clearTimeout(timeoutId);
    timeoutId = setTimeout(() => fn(...args), delay);
  };
};

const debouncedSetKeyword = useCallback(debounce((value: string) => {
  setSearchKeyword(value.toLowerCase());
}, 100), []);

// 输入框 onChange 替换为
onChange={(e) => debouncedSetKeyword(e.target.value)}

内容的提问来源于stack exchange,提问作者Amos Machora

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 13:10:58