Skip to content

性能优化清单 - React应用性能优化全面指南

本文档提供React应用性能优化的完整检查清单,涵盖各个层面的优化策略。

1. 组件渲染优化

1.1 避免不必要的重渲染

tsx
// ✅ 使用React.memo
const MemoizedComponent = React.memo(function Component({ data }) {
  return <div>{data}</div>;
});

// ✅ 自定义比较函数
const MemoizedList = React.memo(
  function List({ items }) {
    return items.map(item => <div key={item.id}>{item.name}</div>);
  },
  (prevProps, nextProps) => {
    return prevProps.items.length === nextProps.items.length &&
           prevProps.items.every((item, i) => item.id === nextProps.items[i].id);
  }
);

// ✅ useMemo缓存昂贵计算
const sortedData = useMemo(() => 
  data.sort((a, b) => a.value - b.value),
  [data]
);

// ✅ useCallback稳定函数引用
const handleClick = useCallback(() => {
  console.log(data);
}, [data]);

// ✅ 状态下放
// ❌ 不好
function Parent() {
  const [text, setText] = useState('');
  return (
    <div>
      <input value={text} onChange={e => setText(e.target.value)} />
      <ExpensiveChild /> {/* text变化时不必要渲染 */}
    </div>
  );
}

// ✅ 好
function Parent() {
  return (
    <div>
      <TextInput />
      <ExpensiveChild />
    </div>
  );
}

function TextInput() {
  const [text, setText] = useState('');
  return <input value={text} onChange={e => setText(e.target.value)} />;
}

1.2 优化列表渲染

tsx
// ✅ 使用key
items.map(item => <Item key={item.id} data={item} />);

// ✅ 虚拟滚动 (react-window)
import { FixedSizeList } from 'react-window';

function VirtualList({ items }) {
  return (
    <FixedSizeList
      height={600}
      itemCount={items.length}
      itemSize={50}
      width="100%"
    >
      {({ index, style }) => (
        <div style={style}>{items[index]}</div>
      )}
    </FixedSizeList>
  );
}

// ✅ 分页/无限滚动
function PaginatedList({ items, pageSize = 20 }) {
  const [page, setPage] = useState(1);
  const paginatedItems = items.slice(0, page * pageSize);
  
  return (
    <div>
      {paginatedItems.map(item => <Item key={item.id} data={item} />)}
      {page * pageSize < items.length && (
        <button onClick={() => setPage(p => p + 1)}>Load More</button>
      )}
    </div>
  );
}

2. 代码分割

2.1 路由级别

tsx
// ✅ 懒加载路由组件
import { lazy, Suspense } from 'react';
import { BrowserRouter, Routes, Route } from 'react-router-dom';

const Home = lazy(() => import('./pages/Home'));
const About = lazy(() => import('./pages/About'));
const Dashboard = lazy(() => import('./pages/Dashboard'));

function App() {
  return (
    <BrowserRouter>
      <Suspense fallback={<Loading />}>
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/about" element={<About />} />
          <Route path="/dashboard" element={<Dashboard />} />
        </Routes>
      </Suspense>
    </BrowserRouter>
  );
}

2.2 组件级别

tsx
// ✅ 按需加载大型组件
const HeavyChart = lazy(() => import('./HeavyChart'));

function Dashboard() {
  const [showChart, setShowChart] = useState(false);
  
  return (
    <div>
      <button onClick={() => setShowChart(true)}>Show Chart</button>
      {showChart && (
        <Suspense fallback={<Spinner />}>
          <HeavyChart />
        </Suspense>
      )}
    </div>
  );
}

2.3 库级别

tsx
// ✅ 动态导入大型库
const loadChartLibrary = async () => {
  const Chart = await import('chart.js');
  return Chart;
};

function ChartComponent() {
  const [Chart, setChart] = useState(null);
  
  useEffect(() => {
    loadChartLibrary().then(setChart);
  }, []);
  
  if (!Chart) return <Spinner />;
  
  return <Chart.Line data={data} />;
}

3. 图片优化

3.1 懒加载图片

tsx
// ✅ 使用Intersection Observer
function LazyImage({ src, alt }) {
  const [imageSrc, setImageSrc] = useState(null);
  const imgRef = useRef();
  
  useEffect(() => {
    const observer = new IntersectionObserver(
      ([entry]) => {
        if (entry.isIntersecting) {
          setImageSrc(src);
          observer.disconnect();
        }
      },
      { threshold: 0.1 }
    );
    
    if (imgRef.current) {
      observer.observe(imgRef.current);
    }
    
    return () => observer.disconnect();
  }, [src]);
  
  return (
    <img
      ref={imgRef}
      src={imageSrc || 'placeholder.jpg'}
      alt={alt}
    />
  );
}

3.2 响应式图片

tsx
// ✅ 使用srcset
function ResponsiveImage({ src, alt }) {
  return (
    <img
      src={src}
      srcSet={`
        ${src}?w=400 400w,
        ${src}?w=800 800w,
        ${src}?w=1200 1200w
      `}
      sizes="(max-width: 600px) 400px, (max-width: 900px) 800px, 1200px"
      alt={alt}
    />
  );
}

3.3 Next.js Image组件

tsx
// ✅ 使用Next.js优化图片
import Image from 'next/image';

function OptimizedImage() {
  return (
    <Image
      src="/hero.jpg"
      alt="Hero"
      width={800}
      height={600}
      placeholder="blur"
      priority
    />
  );
}

4. 网络优化

4.1 数据缓存

tsx
// ✅ 使用React Query缓存
import { useQuery } from '@tanstack/react-query';

function Users() {
  const { data, isLoading } = useQuery({
    queryKey: ['users'],
    queryFn: fetchUsers,
    staleTime: 5 * 60 * 1000, // 5分钟
    cacheTime: 10 * 60 * 1000 // 10分钟
  });
  
  if (isLoading) return <Spinner />;
  
  return <UserList users={data} />;
}

4.2 请求合并

tsx
// ✅ 使用DataLoader模式
import DataLoader from 'dataloader';

const userLoader = new DataLoader(async (ids) => {
  const users = await fetchUsersByIds(ids);
  return ids.map(id => users.find(u => u.id === id));
});

// 多个组件请求相同用户时会自动合并
function User({ userId }) {
  const [user, setUser] = useState(null);
  
  useEffect(() => {
    userLoader.load(userId).then(setUser);
  }, [userId]);
  
  return <div>{user?.name}</div>;
}

4.3 预取数据

tsx
// ✅ 鼠标悬停时预取
import { useQueryClient } from '@tanstack/react-query';

function ProductCard({ product }) {
  const queryClient = useQueryClient();
  
  const prefetchDetails = () => {
    queryClient.prefetchQuery({
      queryKey: ['product', product.id],
      queryFn: () => fetchProductDetails(product.id)
    });
  };
  
  return (
    <div onMouseEnter={prefetchDetails}>
      <Link to={`/products/${product.id}`}>
        {product.name}
      </Link>
    </div>
  );
}

5. 并发特性

5.1 useTransition

tsx
// ✅ 标记非紧急更新
import { useState, useTransition } from 'react';

function SearchComponent() {
  const [query, setQuery] = useState('');
  const [results, setResults] = useState([]);
  const [isPending, startTransition] = useTransition();
  
  const handleChange = (e) => {
    const value = e.target.value;
    setQuery(value); // 紧急更新,立即响应
    
    startTransition(() => {
      // 非紧急更新,可以延迟
      const searchResults = performExpensiveSearch(value);
      setResults(searchResults);
    });
  };
  
  return (
    <div>
      <input value={query} onChange={handleChange} />
      {isPending && <Spinner />}
      <SearchResults results={results} />
    </div>
  );
}

5.2 useDeferredValue

tsx
// ✅ 延迟值更新
import { useState, useDeferredValue, useMemo } from 'react';

function SearchResults({ query }) {
  const deferredQuery = useDeferredValue(query);
  
  const results = useMemo(() => {
    return performExpensiveSearch(deferredQuery);
  }, [deferredQuery]);
  
  return <ResultList results={results} />;
}

function SearchApp() {
  const [query, setQuery] = useState('');
  
  return (
    <div>
      <input
        value={query}
        onChange={e => setQuery(e.target.value)}
      />
      <SearchResults query={query} />
    </div>
  );
}

6. Bundle优化

6.1 Tree Shaking

tsx
// ✅ 使用命名导入
import { debounce } from 'lodash-es';

// ❌ 避免默认导入整个库
import _ from 'lodash';

6.2 动态导入

tsx
// ✅ 按需加载
const handleExport = async () => {
  const { exportToExcel } = await import('./exportUtils');
  exportToExcel(data);
};

6.3 分析Bundle

bash
# 使用webpack-bundle-analyzer
npm install --save-dev webpack-bundle-analyzer

# 或者使用vite-plugin-visualizer
npm install --save-dev rollup-plugin-visualizer

7. Web Vitals优化

7.1 LCP优化

tsx
// ✅ 预加载关键资源
<link rel="preload" as="image" href="/hero.jpg" />

// ✅ 优化图片
// 使用WebP格式、懒加载、响应式图片

// ✅ 服务端渲染
// 使用Next.js等框架的SSR功能

7.2 FID优化

tsx
// ✅ 代码分割减少主线程阻塞
// ✅ 使用Web Workers处理计算密集任务

const worker = new Worker('/heavy-computation-worker.js');

worker.postMessage({ data });
worker.onmessage = (e) => {
  setResult(e.data);
};

7.3 CLS优化

tsx
// ✅ 为图片设置width和height
<img src="/image.jpg" width={800} height={600} alt="Image" />

// ✅ 为动态内容预留空间
<div style={{ minHeight: '200px' }}>
  {loading ? <Skeleton /> : <Content />}
</div>

// ✅ 使用CSS aspect-ratio
.image-container {
  aspect-ratio: 16 / 9;
}

8. 性能监控

8.1 Web Vitals测量

tsx
import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';

function reportWebVitals(metric) {
  console.log(metric);
  // 发送到分析服务
  sendToAnalytics(metric);
}

getCLS(reportWebVitals);
getFID(reportWebVitals);
getFCP(reportWebVitals);
getLCP(reportWebVitals);
getTTFB(reportWebVitals);

8.2 React Profiler

tsx
import { Profiler } from 'react';

function onRenderCallback(
  id,
  phase,
  actualDuration,
  baseDuration,
  startTime,
  commitTime
) {
  console.log({ id, phase, actualDuration });
}

function App() {
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <MainContent />
    </Profiler>
  );
}

9. 性能优化清单

typescript
const performanceChecklist = {
  组件优化: [
    '✅ 使用React.memo避免不必要渲染',
    '✅ 使用useMemo缓存昂贵计算',
    '✅ 使用useCallback稳定函数引用',
    '✅ 避免内联对象/数组/函数',
    '✅ 状态下放到需要的组件',
    '✅ 使用children prop避免重渲染'
  ],
  
  列表优化: [
    '✅ 使用正确的key',
    '✅ 大列表使用虚拟滚动',
    '✅ 实现分页或无限滚动',
    '✅ 优化列表项渲染'
  ],
  
  代码分割: [
    '✅ 路由级别懒加载',
    '✅ 组件级别懒加载',
    '✅ 第三方库按需导入',
    '✅ 使用动态import'
  ],
  
  资源优化: [
    '✅ 图片懒加载',
    '✅ 使用WebP格式',
    '✅ 响应式图片',
    '✅ 使用CDN'
  ],
  
  网络优化: [
    '✅ 启用HTTP/2',
    '✅ 使用缓存策略',
    '✅ 数据预取',
    '✅ 请求合并'
  ],
  
  并发特性: [
    '✅ 使用useTransition',
    '✅ 使用useDeferredValue',
    '✅ 利用Suspense',
    '✅ 利用React 18自动批量更新'
  ],
  
  构建优化: [
    '✅ Tree Shaking',
    '✅ 代码压缩',
    '✅ Gzip/Brotli压缩',
    '✅ 分析Bundle大小'
  ],
  
  监控: [
    '✅ 测量Web Vitals',
    '✅ 使用React Profiler',
    '✅ 设置性能预算',
    '✅ 持续监控'
  ]
};

10. 性能预算

javascript
// 设置性能预算
const performanceBudget = {
  FCP: 1.8, // 秒
  LCP: 2.5,
  FID: 0.1,
  CLS: 0.1,
  TTI: 3.8,
  bundleSize: {
    main: 200, // KB
    vendor: 500,
    total: 1000
  }
};

// 在CI/CD中检查
if (metrics.LCP > performanceBudget.LCP) {
  throw new Error('LCP超出预算');
}

11. 总结

性能优化是一个持续的过程:

  1. 测量: 使用工具测量关键指标
  2. 分析: 找出性能瓶颈
  3. 优化: 应用优化策略
  4. 验证: 确认优化效果
  5. 监控: 持续监控性能

遵循本清单可以系统地优化React应用性能,提供更好的用户体验。