Skip to content

性能优化策略总结 - React性能优化完全指南

1. 性能优化概述

1.1 性能指标

typescript
const performanceMetrics = {
  核心指标: {
    FCP: 'First Contentful Paint - 首次内容绘制',
    LCP: 'Largest Contentful Paint - 最大内容绘制',
    FID: 'First Input Delay - 首次输入延迟',
    CLS: 'Cumulative Layout Shift - 累积布局偏移',
    TTI: 'Time to Interactive - 可交互时间',
    TBT: 'Total Blocking Time - 总阻塞时间'
  },
  
  React特定: {
    初次渲染: '首次加载和渲染时间',
    更新性能: '状态更新触发的渲染时间',
    内存使用: '组件树和状态占用的内存',
    Bundle大小: 'JavaScript包大小'
  },
  
  优化目标: {
    FCP: '< 1.8s',
    LCP: '< 2.5s',
    FID: '< 100ms',
    CLS: '< 0.1',
    TTI: '< 3.8s'
  }
};

1.2 性能瓶颈分类

typescript
const performanceBottlenecks = {
  渲染性能: [
    '不必要的重渲染',
    '大列表渲染',
    '深层组件树',
    '昂贵的计算'
  ],
  
  网络性能: [
    'Bundle体积过大',
    '资源加载慢',
    'API请求慢',
    '未优化图片'
  ],
  
  运行时性能: [
    '内存泄漏',
    '事件处理器过多',
    'DOM操作频繁',
    '动画卡顿'
  ],
  
  加载性能: [
    '首屏加载慢',
    '代码分割不足',
    '未使用懒加载',
    '同步脚本阻塞'
  ]
};

2. 渲染优化策略

2.1 React.memo

typescript
const reactMemoStrategy = {
  作用: '避免函数组件不必要的重渲染',
  
  基本用法: `
    const MyComponent = React.memo(function MyComponent({ value }) {
      console.log('Rendering...');
      return <div>{value}</div>;
    });
    
    // 只有props变化时才重渲染
  `,
  
  自定义比较: `
    const MyComponent = React.memo(
      function MyComponent({ user }) {
        return <div>{user.name}</div>;
      },
      (prevProps, nextProps) => {
        // 返回true表示props相等,不重渲染
        // 返回false表示props不等,重渲染
        return prevProps.user.id === nextProps.user.id;
      }
    );
  `,
  
  使用场景: [
    '纯展示组件',
    '接收大量props的组件',
    '渲染昂贵的组件',
    '列表项组件',
    '频繁重渲染的父组件的子组件'
  ],
  
  注意事项: [
    'memo本身有开销',
    '不要过度使用',
    'props比较是浅比较',
    '对象/数组props需要稳定引用'
  ]
};

2.2 useMemo和useCallback

typescript
const memoHooksStrategy = {
  useMemo: {
    作用: '缓存计算结果',
    示例: `
      function Component({ items }) {
        // 缓存昂贵计算
        const sortedItems = useMemo(() => {
          console.log('Sorting...');
          return items.sort((a, b) => a.value - b.value);
        }, [items]);
        
        return <List items={sortedItems} />;
      }
    `,
    场景: [
      '昂贵计算',
      '引用稳定性',
      'useEffect依赖',
      '传递给memo组件'
    ]
  },
  
  useCallback: {
    作用: '缓存函数引用',
    示例: `
      function Component() {
        const [count, setCount] = useState(0);
        
        // 缓存函数引用
        const handleClick = useCallback(() => {
          setCount(c => c + 1);
        }, []);
        
        return <MemoButton onClick={handleClick} />;
      }
    `,
    场景: [
      '传递给memo子组件',
      'useEffect依赖',
      '自定义Hook返回',
      '防止子组件重建'
    ]
  },
  
  最佳实践: `
    // ✓ 好的使用
    function Parent() {
      const [filter, setFilter] = useState('');
      const [items] = useState(LARGE_ARRAY);
      
      // 昂贵计算使用useMemo
      const filtered = useMemo(() => 
        items.filter(item => item.name.includes(filter)),
        [items, filter]
      );
      
      // 传递给memo组件的函数使用useCallback
      const handleSelect = useCallback((id) => {
        console.log('Selected:', id);
      }, []);
      
      return (
        <>
          <input value={filter} onChange={e => setFilter(e.target.value)} />
          <MemoList items={filtered} onSelect={handleSelect} />
        </>
      );
    }
    
    const MemoList = React.memo(({ items, onSelect }) => {
      return items.map(item => (
        <Item key={item.id} item={item} onSelect={onSelect} />
      ));
    });
  `
};

2.3 组件拆分

typescript
const componentSplitting = {
  问题: `
    // ❌ 大组件,任何state变化都重渲染整个组件
    function BigComponent() {
      const [count, setCount] = useState(0);
      const [items, setItems] = useState([]);
      const [filter, setFilter] = useState('');
      
      return (
        <div>
          <div>
            <h1>Count: {count}</h1>
            <button onClick={() => setCount(c => c + 1)}>+</button>
          </div>
          
          <div>
            <input value={filter} onChange={e => setFilter(e.target.value)} />
            <ul>
              {items.filter(i => i.includes(filter)).map(i => (
                <li key={i}>{i}</li>
              ))}
            </ul>
          </div>
        </div>
      );
    }
  `,
  
  优化: `
    // ✓ 拆分成独立组件
    function Page() {
      return (
        <div>
          <Counter />      {/* count变化不影响List */}
          <FilteredList /> {/* filter变化不影响Counter */}
        </div>
      );
    }
    
    function Counter() {
      const [count, setCount] = useState(0);
      
      return (
        <div>
          <h1>Count: {count}</h1>
          <button onClick={() => setCount(c => c + 1)}>+</button>
        </div>
      );
    }
    
    function FilteredList() {
      const [items, setItems] = useState([]);
      const [filter, setFilter] = useState('');
      
      const filtered = useMemo(
        () => items.filter(i => i.includes(filter)),
        [items, filter]
      );
      
      return (
        <div>
          <input value={filter} onChange={e => setFilter(e.target.value)} />
          <ul>
            {filtered.map(i => <li key={i}>{i}</li>)}
          </ul>
        </div>
      );
    }
  `
};

3. 列表优化

3.1 虚拟滚动

typescript
const virtualScrolling = {
  问题: '渲染大量列表项',
  
  解决: 'react-window或react-virtualized',
  
  示例: `
    import { FixedSizeList } from 'react-window';
    
    function LargeList({ items }) {
      const Row = ({ index, style }) => (
        <div style={style}>
          {items[index].name}
        </div>
      );
      
      return (
        <FixedSizeList
          height={400}
          itemCount={items.length}
          itemSize={35}
          width="100%"
        >
          {Row}
        </FixedSizeList>
      );
    }
    
    // 只渲染可见区域的项
    // 10000项 -> 只渲染约15项
  `,
  
  性能对比: {
    传统: '渲染10000个DOM节点',
    虚拟滚动: '渲染15个DOM节点',
    提升: '约99%'
  }
};

3.2 Key优化

typescript
const keyOptimization = {
  稳定Key: `
    // ✓ 使用稳定的唯一ID
    {items.map(item => (
      <Item key={item.id} {...item} />
    ))}
  `,
  
  避免索引: `
    // ❌ 避免使用索引(除非列表静态)
    {items.map((item, index) => (
      <Item key={index} {...item} />
    ))}
    
    // 问题: 插入/删除/重排序会导致key错位
  `,
  
  复合Key: `
    // 多数据源时使用复合key
    {items.map(item => (
      <Item key={\`\${item.type}-\${item.id}\`} {...item} />
    ))}
  `
};

3.3 懒加载

typescript
const lazyLoading = {
  组件懒加载: `
    import { lazy, Suspense } from 'react';
    
    const HeavyComponent = lazy(() => import('./HeavyComponent'));
    
    function App() {
      return (
        <Suspense fallback={<Loading />}>
          <HeavyComponent />
        </Suspense>
      );
    }
  `,
  
  路由懒加载: `
    const Home = lazy(() => import('./pages/Home'));
    const About = lazy(() => import('./pages/About'));
    const Contact = lazy(() => import('./pages/Contact'));
    
    function App() {
      return (
        <BrowserRouter>
          <Suspense fallback={<PageLoader />}>
            <Routes>
              <Route path="/" element={<Home />} />
              <Route path="/about" element={<About />} />
              <Route path="/contact" element={<Contact />} />
            </Routes>
          </Suspense>
        </BrowserRouter>
      );
    }
  `,
  
  图片懒加载: `
    function ImageList({ images }) {
      return images.map(img => (
        <img
          key={img.id}
          src={img.url}
          loading="lazy"  // 原生懒加载
          alt={img.alt}
        />
      ));
    }
  `
};

4. Bundle优化

4.1 代码分割

typescript
const codeSplitting = {
  动态导入: `
    // 按需加载
    function Component() {
      const [show, setShow] = useState(false);
      const [Module, setModule] = useState(null);
      
      const loadModule = async () => {
        const mod = await import('./HeavyModule');
        setModule(() => mod.default);
        setShow(true);
      };
      
      return (
        <div>
          <button onClick={loadModule}>Load Module</button>
          {show && Module && <Module />}
        </div>
      );
    }
  `,
  
  路由分割: '每个路由一个chunk',
  
  vendor分割: `
    // webpack配置
    optimization: {
      splitChunks: {
        chunks: 'all',
        cacheGroups: {
          vendor: {
            test: /node_modules/,
            name: 'vendors',
            priority: 10
          },
          common: {
            minChunks: 2,
            name: 'common',
            priority: 5
          }
        }
      }
    }
  `
};

4.2 Tree Shaking

typescript
const treeShaking = {
  原理: '移除未使用的代码',
  
  ES模块: `
    // ✓ 支持tree shaking
    import { func1, func2 } from 'utils';
    
    // ❌ 不支持tree shaking  
    const utils = require('utils');
  `,
  
  按需导入: `
    // ❌ 导入整个库
    import _ from 'lodash';
    
    // ✓ 只导入需要的
    import debounce from 'lodash/debounce';
    import throttle from 'lodash/throttle';
    
    // 或使用es版本
    import { debounce, throttle } from 'lodash-es';
  `,
  
  副作用: `
    // package.json
    {
      "sideEffects": false  // 标记无副作用,支持tree shaking
    }
    
    // 或指定有副作用的文件
    {
      "sideEffects": ["*.css", "*.scss"]
    }
  `
};

5. 状态管理优化

5.1 状态提升和下放

typescript
const stateManagement = {
  状态下放: `
    // ❌ 状态在顶层,所有子组件重渲染
    function App() {
      const [filter, setFilter] = useState('');
      
      return (
        <div>
          <Header />  {/* filter变化时重渲染 */}
          <Sidebar /> {/* filter变化时重渲染 */}
          <Content filter={filter} />
          <Footer />  {/* filter变化时重渲染 */}
        </div>
      );
    }
    
    // ✓ 状态下放到需要的组件
    function App() {
      return (
        <div>
          <Header />  {/* 不受filter影响 */}
          <Sidebar />
          <ContentWithFilter />
          <Footer />
        </div>
      );
    }
    
    function ContentWithFilter() {
      const [filter, setFilter] = useState('');
      return <Content filter={filter} />;
    }
  `,
  
  状态分割: `
    // ❌ 大对象状态
    const [state, setState] = useState({
      user: null,
      posts: [],
      comments: [],
      settings: {}
    });
    
    // user变化导致整个组件重渲染
    
    // ✓ 分割状态
    const [user, setUser] = useState(null);
    const [posts, setPosts] = useState([]);
    const [comments, setComments] = useState([]);
    const [settings, setSettings] = useState({});
    
    // 各自独立更新
  `
};

5.2 Context优化

typescript
const contextOptimization = {
  问题: `
    // ❌ 单一Context包含所有状态
    const AppContext = createContext();
    
    function App() {
      const [user, setUser] = useState(null);
      const [theme, setTheme] = useState('light');
      const [lang, setLang] = useState('en');
      
      const value = { user, setUser, theme, setTheme, lang, setLang };
      
      return (
        <AppContext.Provider value={value}>
          <Page />
        </AppContext.Provider>
      );
    }
    
    // 问题: value每次都是新对象,所有消费者都重渲染
  `,
  
  优化1_分离Context: `
    // ✓ 按功能分离Context
    const UserContext = createContext();
    const ThemeContext = createContext();
    const LangContext = createContext();
    
    function App() {
      const [user, setUser] = useState(null);
      const [theme, setTheme] = useState('light');
      const [lang, setLang] = useState('en');
      
      return (
        <UserContext.Provider value={{ user, setUser }}>
          <ThemeContext.Provider value={{ theme, setTheme }}>
            <LangContext.Provider value={{ lang, setLang }}>
              <Page />
            </LangContext.Provider>
          </ThemeContext.Provider>
        </UserContext.Provider>
      );
    }
  `,
  
  优化2_Memo_value: `
    // ✓ 缓存value对象
    function App() {
      const [user, setUser] = useState(null);
      const [theme, setTheme] = useState('light');
      
      const userValue = useMemo(
        () => ({ user, setUser }),
        [user]
      );
      
      const themeValue = useMemo(
        () => ({ theme, setTheme }),
        [theme]
      );
      
      return (
        <UserContext.Provider value={userValue}>
          <ThemeContext.Provider value={themeValue}>
            <Page />
          </ThemeContext.Provider>
        </UserContext.Provider>
      );
    }
  `,
  
  优化3_分离state和dispatch: `
    // ✓ 状态和dispatch分离
    const StateContext = createContext();
    const DispatchContext = createContext();
    
    function Provider({ children }) {
      const [state, dispatch] = useReducer(reducer, initialState);
      
      return (
        <DispatchContext.Provider value={dispatch}>
          <StateContext.Provider value={state}>
            {children}
          </StateContext.Provider>
        </DispatchContext.Provider>
      );
    }
    
    // dispatch永不变化,消费dispatch的组件不重渲染
  `
};

6. 网络优化

6.1 Bundle优化

typescript
const bundleOptimization = {
  分析Bundle: `
    // webpack-bundle-analyzer
    npm install --save-dev webpack-bundle-analyzer
    
    // webpack.config.js
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    
    module.exports = {
      plugins: [
        new BundleAnalyzerPlugin()
      ]
    };
  `,
  
  压缩: `
    // Vite自动压缩
    // webpack需要配置
    const TerserPlugin = require('terser-webpack-plugin');
    
    optimization: {
      minimize: true,
      minimizer: [new TerserPlugin({
        terserOptions: {
          compress: {
            drop_console: true  // 移除console
          }
        }
      })]
    }
  `,
  
  Gzip: `
    // compression-webpack-plugin
    const CompressionPlugin = require('compression-webpack-plugin');
    
    plugins: [
      new CompressionPlugin({
        algorithm: 'gzip',
        test: /\\.js$|\\.css$|\\.html$/,
        threshold: 10240,
        minRatio: 0.8
      })
    ]
  `
};

6.2 资源优化

typescript
const resourceOptimization = {
  图片优化: `
    // 使用WebP格式
    <picture>
      <source srcSet="image.webp" type="image/webp" />
      <img src="image.jpg" alt="Fallback" />
    </picture>
    
    // 响应式图片
    <img
      srcSet="
        small.jpg 300w,
        medium.jpg 768w,
        large.jpg 1200w
      "
      sizes="(max-width: 768px) 100vw, 50vw"
      src="fallback.jpg"
      alt="Image"
    />
    
    // 懒加载
    <img src="image.jpg" loading="lazy" alt="Image" />
  `,
  
  字体优化: `
    // 字体子集化
    @font-face {
      font-family: 'MyFont';
      src: url('/fonts/myfont-subset.woff2') format('woff2');
      font-display: swap;  // 显示fallback字体
      unicode-range: U+0-7F;  // 只包含ASCII
    }
    
    // 预加载关键字体
    <link
      rel="preload"
      href="/fonts/critical.woff2"
      as="font"
      type="font/woff2"
      crossOrigin="anonymous"
    />
  `,
  
  CDN: `
    // 使用CDN加速静态资源
    const CDN_URL = 'https://cdn.example.com';
    
    function Image({ src, alt }) {
      return <img src={\`\${CDN_URL}\${src}\`} alt={alt} />;
    }
  `
};

7. 监控和分析

7.1 性能监控工具

typescript
const monitoringTools = {
  React_DevTools: {
    功能: ['Profiler', '组件树', 'Hooks检查'],
    使用: '浏览器扩展'
  },
  
  Chrome_DevTools: {
    Performance: '记录和分析性能',
    Lighthouse: '性能审计',
    Coverage: '代码覆盖率'
  },
  
  Web_Vitals: `
    import { getCLS, getFID, getFCP, getLCP, getTTFB } from 'web-vitals';
    
    function sendToAnalytics({ name, value, id }) {
      // 发送到分析服务
      console.log({ name, value, id });
    }
    
    getCLS(sendToAnalytics);
    getFID(sendToAnalytics);
    getFCP(sendToAnalytics);
    getLCP(sendToAnalytics);
    getTTFB(sendToAnalytics);
  `
};

8. 面试高频问题

typescript
const interviewQA = {
  Q1: {
    question: 'React性能优化的主要方法?',
    answer: [
      '1. React.memo避免重渲染',
      '2. useMemo缓存计算结果',
      '3. useCallback缓存函数',
      '4. 代码分割和懒加载',
      '5. 虚拟滚动处理大列表',
      '6. 使用key优化列表',
      '7. Context优化',
      '8. Bundle优化'
    ]
  },
  
  Q2: {
    question: '如何优化大列表渲染?',
    answer: [
      '1. 虚拟滚动(react-window)',
      '2. 分页加载',
      '3. 使用稳定key',
      '4. React.memo列表项',
      '5. 避免内联函数',
      '6. 懒加载图片'
    ]
  },
  
  Q3: {
    question: '如何减小Bundle大小?',
    answer: [
      '1. 代码分割',
      '2. Tree Shaking',
      '3. 按需导入',
      '4. 移除未使用依赖',
      '5. 压缩代码',
      '6. 使用轻量级替代库'
    ]
  }
};

9. 总结

React性能优化策略的核心要点:

  1. 渲染优化: memo/useMemo/useCallback
  2. 列表优化: 虚拟滚动/key/懒加载
  3. Bundle优化: 代码分割/Tree Shaking
  4. 网络优化: CDN/压缩/缓存
  5. 监控: DevTools/Web Vitals
  6. 状态管理: 合理拆分/Context优化

掌握这些策略可以显著提升React应用性能。