React 性能优化完全指南

React 性能优化完全指南

Your Name
6 min read

React 性能优化完全指南

性能优化是构建优秀 React 应用的关键。本文将介绍一系列实用的优化技巧。

1. 使用 React.memo 避免不必要的重渲染

import React, { memo } from 'react';

interface Props {
  title: string;
  count: number;
}

// 只有当 props 改变时才重新渲染
const ExpensiveComponent = memo<Props>(({ title, count }) => {
  console.log('Rendering ExpensiveComponent');
  return (
    <div>
      <h2>{title}</h2>
      <p>Count: {count}</p>
    </div>
  );
});

// 自定义比较函数
const ExpensiveComponentWithCustomCompare = memo<Props>(
  ({ title, count }) => {
    return (
      <div>
        <h2>{title}</h2>
        <p>Count: {count}</p>
      </div>
    );
  },
  (prevProps, nextProps) => {
    // 返回 true 表示不需要重新渲染
    return prevProps.count === nextProps.count;
  },
);

2. useMemo 和 useCallback

useMemo - 缓存计算结果

import { useMemo } from 'react';

function DataList({ items, filter }) {
  // 只有当 items 或 filter 改变时才重新计算
  const filteredItems = useMemo(() => {
    console.log('Filtering items...');
    return items.filter((item) => item.category === filter);
  }, [items, filter]);

  return (
    <ul>
      {filteredItems.map((item) => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

useCallback - 缓存函数引用

import { useCallback, useState } from 'react';

function ParentComponent() {
  const [count, setCount] = useState(0);

  // 缓存函数引用,避免子组件不必要的重渲染
  const handleClick = useCallback(() => {
    setCount((c) => c + 1);
  }, []); // 空依赖数组,函数引用永不改变

  return (
    <div>
      <p>Count: {count}</p>
      <ChildComponent onClick={handleClick} />
    </div>
  );
}

const ChildComponent = memo(({ onClick }) => {
  console.log('Child rendered');
  return <button onClick={onClick}>Increment</button>;
});

3. 代码分割和懒加载

import { lazy, Suspense } from 'react';

// 懒加载组件
const HeavyComponent = lazy(() => import('./HeavyComponent'));

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <HeavyComponent />
    </Suspense>
  );
}

4. 虚拟列表

对于长列表,使用虚拟滚动:

import { FixedSizeList } from 'react-window';

function VirtualList({ items }) {
  const Row = ({ index, style }) => <div style={style}>{items[index].name}</div>;

  return (
    <FixedSizeList height={600} itemCount={items.length} itemSize={50} width="100%">
      {Row}
    </FixedSizeList>
  );
}

5. 图片优化

import Image from 'next/image';

// Next.js 自动优化图片
<Image
  src="/large-image.jpg"
  alt="Description"
  width={800}
  height={600}
  loading="lazy" // 懒加载
  placeholder="blur" // 模糊占位符
/>

// 原生 React 懒加载
<img
  src="/image.jpg"
  alt="Description"
  loading="lazy"
  decoding="async"
/>

6. 避免内联对象和函数

// ❌ 不推荐 - 每次渲染都创建新对象
function BadComponent() {
  return <Child style={{ margin: 10 }} onClick={() => console.log('clicked')} />;
}

// ✅ 推荐
function GoodComponent() {
  const style = useMemo(() => ({ margin: 10 }), []);
  const handleClick = useCallback(() => console.log('clicked'), []);

  return <Child style={style} onClick={handleClick} />;
}

7. 使用 Web Workers 处理密集计算

// worker.ts
self.onmessage = (e) => {
  const result = heavyCalculation(e.data);
  self.postMessage(result);
};

// Component.tsx
import { useEffect, useState } from 'react';

function Component() {
  const [result, setResult] = useState(null);

  useEffect(() => {
    const worker = new Worker(new URL('./worker.ts', import.meta.url));

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

    worker.postMessage({ data: largeDataset });

    return () => worker.terminate();
  }, []);

  return <div>{result}</div>;
}

8. 使用 startTransition 标记非紧急更新

import { startTransition, useState } from 'react';

function SearchComponent() {
  const [input, setInput] = useState('');
  const [results, setResults] = useState([]);

  const handleChange = (e) => {
    // 紧急更新:立即更新输入框
    setInput(e.target.value);

    // 非紧急更新:可以延迟的搜索结果
    startTransition(() => {
      const filtered = heavySearch(e.target.value);
      setResults(filtered);
    });
  };

  return (
    <>
      <input value={input} onChange={handleChange} />
      <ResultsList results={results} />
    </>
  );
}

9. 性能监控

import { useEffect } from 'react';

function PerformanceMonitor({ children }) {
  useEffect(() => {
    // 监控 Core Web Vitals
    if ('web-vitals' in window) {
      import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {
        getCLS(console.log);
        getFID(console.log);
        getFCP(console.log);
        getLCP(console.log);
        getTTFB(console.log);
      });
    }
  }, []);

  return children;
}

10. 生产环境构建优化

// next.config.js
module.exports = {
  // 压缩输出
  compress: true,

  // 分析包大小
  webpack: (config, { isServer }) => {
    if (!isServer) {
      config.optimization.splitChunks = {
        chunks: 'all',
        cacheGroups: {
          default: false,
          vendors: false,
          vendor: {
            name: 'vendor',
            chunks: 'all',
            test: /node_modules/,
          },
        },
      };
    }
    return config;
  },
};

性能检查清单

  • 使用 React DevTools Profiler 分析组件性能
  • 检查不必要的重渲染
  • 优化大型列表渲染
  • 实现代码分割和懒加载
  • 优化图片加载
  • 使用生产环境构建
  • 启用 Gzip/Brotli 压缩
  • 配置 CDN
  • 实现适当的缓存策略

总结

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

  1. 🔍 测量:使用工具识别性能瓶颈
  2. 优化:应用合适的优化技巧
  3. 📊 监控:持续跟踪性能指标
  4. 🔄 迭代:根据数据不断改进

记住:过早优化是万恶之源。先让代码工作,然后再优化真正的瓶颈。


你还有哪些 React 性能优化的技巧?欢迎分享!

相关文章