Skip to content

性能优化实战对比

学习目标

通过本章学习,你将全面掌握:

  • 各种性能优化方案的对比
  • 性能测量工具的使用
  • 真实场景的优化策略
  • 优化前后的性能差异
  • 性能优化的最佳实践
  • 常见性能陷阱
  • React 19的自动优化
  • 性能监控和分析

第一部分:优化方案全面对比

1.1 未优化vs完全优化

jsx
// ========== 未优化版本 ==========
function UnoptimizedApp() {
  const [count, setCount] = useState(0);
  const [items, setItems] = useState(
    Array.from({ length: 1000 }, (_, i) => ({
      id: i,
      name: `Item ${i}`,
      value: Math.random()
    }))
  );
  
  // 问题1:每次渲染都过滤
  const filteredItems = items.filter(item => item.id % 2 === 0);
  
  // 问题2:每次渲染都排序
  const sortedItems = filteredItems.sort((a, b) => b.value - a.value);
  
  // 问题3:每次渲染创建新函数
  const handleClick = (id) => {
    console.log('点击:', id);
  };
  
  // 问题4:每次渲染创建新对象
  const config = {
    showActions: true,
    editable: false
  };
  
  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>
        更新Count: {count}
      </button>
      
      <p>共 {sortedItems.length} 项</p>
      
      {sortedItems.map(item => (
        <RegularItem
          key={item.id}
          item={item}
          onClick={handleClick}
          config={config}
        />
      ))}
    </div>
  );
}

function RegularItem({ item, onClick, config }) {
  console.log('Item渲染:', item.id);
  
  return (
    <div onClick={() => onClick(item.id)}>
      {item.name}: {item.value.toFixed(3)}
    </div>
  );
}

// ========== 完全优化版本 ==========
function OptimizedApp() {
  const [count, setCount] = useState(0);
  const [items, setItems] = useState(
    Array.from({ length: 1000 }, (_, i) => ({
      id: i,
      name: `Item ${i}`,
      value: Math.random()
    }))
  );
  
  // 优化1:使用useMemo缓存过滤结果
  const filteredItems = useMemo(() => {
    console.log('执行过滤');
    return items.filter(item => item.id % 2 === 0);
  }, [items]);
  
  // 优化2:使用useMemo缓存排序结果
  const sortedItems = useMemo(() => {
    console.log('执行排序');
    return [...filteredItems].sort((a, b) => b.value - a.value);
  }, [filteredItems]);
  
  // 优化3:使用useCallback缓存函数
  const handleClick = useCallback((id) => {
    console.log('点击:', id);
  }, []);
  
  // 优化4:使用useMemo缓存配置对象
  const config = useMemo(() => ({
    showActions: true,
    editable: false
  }), []);
  
  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>
        更新Count: {count}
      </button>
      
      <p>共 {sortedItems.length} 项</p>
      
      {sortedItems.map(item => (
        <OptimizedItem
          key={item.id}
          item={item}
          onClick={handleClick}
          config={config}
        />
      ))}
    </div>
  );
}

// 优化5:使用React.memo包裹组件
const OptimizedItem = React.memo(function Item({ item, onClick, config }) {
  console.log('Item渲染:', item.id);
  
  return (
    <div onClick={() => onClick(item.id)}>
      {item.name}: {item.value.toFixed(3)}
    </div>
  );
});

1.2 性能对比表

jsx
/*
性能对比:

未优化版本:
- 每次count变化时:
  - 过滤1000项:~2ms
  - 排序500项:~1ms
  - 渲染500个组件:~50ms
  - 总计:~53ms
  - 所有Item组件都重新渲染

优化版本:
- 每次count变化时:
  - 过滤:跳过(使用缓存)
  - 排序:跳过(使用缓存)
  - 渲染:跳过(React.memo)
  - 总计:~1ms
  - 没有Item组件重新渲染

性能提升:53倍
*/

第二部分:性能测量工具

2.1 使用React DevTools Profiler

jsx
import { Profiler } from 'react';

function ProfiledApp() {
  const [count, setCount] = useState(0);
  
  const onRenderCallback = (
    id,                // Profiler的id
    phase,             // "mount" 或 "update"
    actualDuration,    // 本次渲染耗时
    baseDuration,      // 不使用memo的估计耗时
    startTime,         // 开始渲染的时间
    commitTime         // 提交更新的时间
  ) => {
    console.log({
      id,
      phase,
      actualDuration: actualDuration.toFixed(2) + 'ms',
      baseDuration: baseDuration.toFixed(2) + 'ms',
      improvement: ((baseDuration - actualDuration) / baseDuration * 100).toFixed(1) + '%'
    });
  };
  
  return (
    <Profiler id="App" onRender={onRenderCallback}>
      <div>
        <button onClick={() => setCount(c => c + 1)}>
          Count: {count}
        </button>
        <ExpensiveComponent />
      </div>
    </Profiler>
  );
}

2.2 自定义性能监控

jsx
function PerformanceMonitor() {
  const renderTimes = useRef([]);
  const renderCount = useRef(0);
  const startTime = useRef(performance.now());
  
  useEffect(() => {
    const endTime = performance.now();
    const duration = endTime - startTime.current;
    
    renderTimes.current.push(duration);
    renderCount.current++;
    
    console.log(`渲染 #${renderCount.current}: ${duration.toFixed(2)}ms`);
    
    if (renderTimes.current.length >= 10) {
      const average = renderTimes.current.reduce((a, b) => a + b, 0) / renderTimes.current.length;
      console.log(`平均渲染时间: ${average.toFixed(2)}ms`);
    }
  });
  
  // 记录开始时间
  startTime.current = performance.now();
  
  return <div>性能监控组件</div>;
}

2.3 性能测试套件

jsx
function PerformanceTestSuite() {
  const [testResults, setTestResults] = useState([]);
  
  const runTest = (name, testFn) => {
    const iterations = 100;
    const times = [];
    
    for (let i = 0; i < iterations; i++) {
      const start = performance.now();
      testFn();
      const end = performance.now();
      times.push(end - start);
    }
    
    const average = times.reduce((a, b) => a + b, 0) / times.length;
    const min = Math.min(...times);
    const max = Math.max(...times);
    
    setTestResults(prev => [...prev, {
      name,
      average: average.toFixed(3),
      min: min.toFixed(3),
      max: max.toFixed(3)
    }]);
  };
  
  const runAllTests = () => {
    setTestResults([]);
    
    runTest('未优化渲染', () => {
      // 测试未优化版本
    });
    
    runTest('优化渲染', () => {
      // 测试优化版本
    });
  };
  
  return (
    <div>
      <button onClick={runAllTests}>运行性能测试</button>
      
      <table>
        <thead>
          <tr>
            <th>测试名称</th>
            <th>平均耗时</th>
            <th>最小耗时</th>
            <th>最大耗时</th>
          </tr>
        </thead>
        <tbody>
          {testResults.map((result, i) => (
            <tr key={i}>
              <td>{result.name}</td>
              <td>{result.average}ms</td>
              <td>{result.min}ms</td>
              <td>{result.max}ms</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

第三部分:真实场景优化

3.1 场景1:社交媒体Feed

jsx
// ===== 未优化版本 =====
function UnoptimizedFeed() {
  const [posts, setPosts] = useState([]);
  const [likedPosts, setLikedPosts] = useState(new Set());
  
  const handleLike = (postId) => {
    setLikedPosts(prev => {
      const newSet = new Set(prev);
      if (newSet.has(postId)) {
        newSet.delete(postId);
      } else {
        newSet.add(postId);
      }
      return newSet;
    });
  };
  
  return (
    <div>
      {posts.map(post => (
        <FeedPost
          key={post.id}
          post={post}
          isLiked={likedPosts.has(post.id)}
          onLike={() => handleLike(post.id)}
        />
      ))}
    </div>
  );
}

function FeedPost({ post, isLiked, onLike }) {
  console.log('FeedPost渲染:', post.id);
  
  return (
    <div className="post">
      <h3>{post.title}</h3>
      <p>{post.content}</p>
      <button onClick={onLike}>
        {isLiked ? '已点赞' : '点赞'} ({post.likes})
      </button>
    </div>
  );
}

// ===== 优化版本 =====
function OptimizedFeed() {
  const [posts, setPosts] = useState([]);
  const [likedPosts, setLikedPosts] = useState(new Set());
  
  // 使用useCallback缓存点赞函数
  const handleLike = useCallback((postId) => {
    setLikedPosts(prev => {
      const newSet = new Set(prev);
      if (newSet.has(postId)) {
        newSet.delete(postId);
      } else {
        newSet.add(postId);
      }
      return newSet;
    });
  }, []);
  
  return (
    <div>
      {posts.map(post => (
        <MemoFeedPost
          key={post.id}
          post={post}
          isLiked={likedPosts.has(post.id)}
          onLike={handleLike}
        />
      ))}
    </div>
  );
}

// 使用React.memo + 自定义比较
const MemoFeedPost = React.memo(
  function FeedPost({ post, isLiked, onLike }) {
    console.log('FeedPost渲染:', post.id);
    
    const handleClick = useCallback(() => {
      onLike(post.id);
    }, [post.id, onLike]);
    
    return (
      <div className="post">
        <h3>{post.title}</h3>
        <p>{post.content}</p>
        <button onClick={handleClick}>
          {isLiked ? '已点赞' : '点赞'} ({post.likes})
        </button>
      </div>
    );
  },
  (prevProps, nextProps) => {
    // 自定义比较:只比较需要的属性
    return prevProps.post.id === nextProps.post.id &&
           prevProps.isLiked === nextProps.isLiked;
  }
);

3.2 场景2:电商商品列表

jsx
// ===== 未优化版本 =====
function UnoptimizedProductList() {
  const [products] = useState(generateProducts(500));
  const [filter, setFilter] = useState('all');
  const [sortBy, setSortBy] = useState('name');
  const [cart, setCart] = useState([]);
  
  // 问题:每次渲染都过滤和排序
  const filteredProducts = products.filter(p => {
    if (filter === 'all') return true;
    return p.category === filter;
  });
  
  const sortedProducts = filteredProducts.sort((a, b) => {
    if (sortBy === 'name') return a.name.localeCompare(b.name);
    if (sortBy === 'price') return a.price - b.price;
    return 0;
  });
  
  const addToCart = (product) => {
    setCart([...cart, product]);
  };
  
  return (
    <div>
      <div>
        <select value={filter} onChange={e => setFilter(e.target.value)}>
          <option value="all">全部</option>
          <option value="electronics">电子产品</option>
          <option value="clothing">服装</option>
        </select>
        
        <select value={sortBy} onChange={e => setSortBy(e.target.value)}>
          <option value="name">按名称</option>
          <option value="price">按价格</option>
        </select>
      </div>
      
      <div className="product-grid">
        {sortedProducts.map(product => (
          <ProductCard
            key={product.id}
            product={product}
            onAddToCart={() => addToCart(product)}
          />
        ))}
      </div>
    </div>
  );
}

function ProductCard({ product, onAddToCart }) {
  console.log('ProductCard渲染:', product.id);
  
  return (
    <div className="product-card">
      <h3>{product.name}</h3>
      <p>¥{product.price}</p>
      <button onClick={onAddToCart}>加入购物车</button>
    </div>
  );
}

// ===== 优化版本 =====
function OptimizedProductList() {
  const [products] = useState(generateProducts(500));
  const [filter, setFilter] = useState('all');
  const [sortBy, setSortBy] = useState('name');
  const [cart, setCart] = useState([]);
  
  // 优化:使用useMemo缓存过滤结果
  const filteredProducts = useMemo(() => {
    console.log('执行过滤');
    return products.filter(p => {
      if (filter === 'all') return true;
      return p.category === filter;
    });
  }, [products, filter]);
  
  // 优化:使用useMemo缓存排序结果
  const sortedProducts = useMemo(() => {
    console.log('执行排序');
    return [...filteredProducts].sort((a, b) => {
      if (sortBy === 'name') return a.name.localeCompare(b.name);
      if (sortBy === 'price') return a.price - b.price;
      return 0;
    });
  }, [filteredProducts, sortBy]);
  
  // 优化:使用useCallback缓存函数
  const addToCart = useCallback((product) => {
    setCart(prev => [...prev, product]);
  }, []);
  
  return (
    <div>
      <div>
        <select value={filter} onChange={e => setFilter(e.target.value)}>
          <option value="all">全部</option>
          <option value="electronics">电子产品</option>
          <option value="clothing">服装</option>
        </select>
        
        <select value={sortBy} onChange={e => setSortBy(e.target.value)}>
          <option value="name">按名称</option>
          <option value="price">按价格</option>
        </select>
      </div>
      
      <div className="product-grid">
        {sortedProducts.map(product => (
          <MemoProductCard
            key={product.id}
            product={product}
            onAddToCart={addToCart}
          />
        ))}
      </div>
    </div>
  );
}

const MemoProductCard = React.memo(function ProductCard({ product, onAddToCart }) {
  console.log('ProductCard渲染:', product.id);
  
  const handleClick = useCallback(() => {
    onAddToCart(product);
  }, [product, onAddToCart]);
  
  return (
    <div className="product-card">
      <h3>{product.name}</h3>
      <p>¥{product.price}</p>
      <button onClick={handleClick}>加入购物车</button>
    </div>
  );
});

function generateProducts(count) {
  return Array.from({ length: count }, (_, i) => ({
    id: i,
    name: `Product ${i}`,
    price: Math.floor(Math.random() * 1000) + 100,
    category: ['electronics', 'clothing'][Math.floor(Math.random() * 2)]
  }));
}

3.3 场景3:数据仪表板

jsx
// ===== 未优化版本 =====
function UnoptimizedDashboard({ rawData }) {
  const [timeRange, setTimeRange] = useState('day');
  const [metric, setMetric] = useState('revenue');
  
  // 问题:每次渲染都处理数据
  const processedData = rawData.filter(d => {
    const date = new Date(d.date);
    const now = new Date();
    
    if (timeRange === 'day') {
      return date.toDateString() === now.toDateString();
    } else if (timeRange === 'week') {
      const weekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);
      return date >= weekAgo;
    }
    return true;
  }).map(d => ({
    ...d,
    value: metric === 'revenue' ? d.revenue : d.orders
  }));
  
  const total = processedData.reduce((sum, d) => sum + d.value, 0);
  const average = total / processedData.length;
  
  return (
    <div>
      <select value={timeRange} onChange={e => setTimeRange(e.target.value)}>
        <option value="day">今天</option>
        <option value="week">本周</option>
        <option value="month">本月</option>
      </select>
      
      <select value={metric} onChange={e => setMetric(e.target.value)}>
        <option value="revenue">收入</option>
        <option value="orders">订单数</option>
      </select>
      
      <StatCard label="总计" value={total} />
      <StatCard label="平均" value={average} />
      <Chart data={processedData} />
    </div>
  );
}

function StatCard({ label, value }) {
  console.log('StatCard渲染:', label);
  return (
    <div>
      <h3>{label}</h3>
      <p>{value.toFixed(2)}</p>
    </div>
  );
}

function Chart({ data }) {
  console.log('Chart渲染');
  return <div>图表: {data.length} 个数据点</div>;
}

// ===== 优化版本 =====
function OptimizedDashboard({ rawData }) {
  const [timeRange, setTimeRange] = useState('day');
  const [metric, setMetric] = useState('revenue');
  
  // 优化:使用useMemo缓存数据处理
  const processedData = useMemo(() => {
    console.log('处理数据');
    
    return rawData.filter(d => {
      const date = new Date(d.date);
      const now = new Date();
      
      if (timeRange === 'day') {
        return date.toDateString() === now.toDateString();
      } else if (timeRange === 'week') {
        const weekAgo = new Date(now - 7 * 24 * 60 * 60 * 1000);
        return date >= weekAgo;
      }
      return true;
    }).map(d => ({
      ...d,
      value: metric === 'revenue' ? d.revenue : d.orders
    }));
  }, [rawData, timeRange, metric]);
  
  // 优化:使用useMemo缓存统计计算
  const statistics = useMemo(() => {
    console.log('计算统计');
    
    const total = processedData.reduce((sum, d) => sum + d.value, 0);
    const average = processedData.length > 0 ? total / processedData.length : 0;
    const max = Math.max(...processedData.map(d => d.value));
    const min = Math.min(...processedData.map(d => d.value));
    
    return { total, average, max, min };
  }, [processedData]);
  
  return (
    <div>
      <select value={timeRange} onChange={e => setTimeRange(e.target.value)}>
        <option value="day">今天</option>
        <option value="week">本周</option>
        <option value="month">本月</option>
      </select>
      
      <select value={metric} onChange={e => setMetric(e.target.value)}>
        <option value="revenue">收入</option>
        <option value="orders">订单数</option>
      </select>
      
      <MemoStatCard label="总计" value={statistics.total} />
      <MemoStatCard label="平均" value={statistics.average} />
      <MemoStatCard label="最大" value={statistics.max} />
      <MemoStatCard label="最小" value={statistics.min} />
      <MemoChart data={processedData} />
    </div>
  );
}

const MemoStatCard = React.memo(function StatCard({ label, value }) {
  console.log('StatCard渲染:', label);
  return (
    <div className="stat-card">
      <h3>{label}</h3>
      <p>{value.toFixed(2)}</p>
    </div>
  );
});

const MemoChart = React.memo(function Chart({ data }) {
  console.log('Chart渲染');
  
  // 图表渲染逻辑
  return (
    <div className="chart">
      图表: {data.length} 个数据点
    </div>
  );
});

3.4 场景4:聊天应用

jsx
// ===== 优化版聊天应用 =====
function OptimizedChatApp() {
  const [messages, setMessages] = useState([]);
  const [inputText, setInputText] = useState('');
  const [filter, setFilter] = useState('all');
  
  // 过滤消息
  const filteredMessages = useMemo(() => {
    if (filter === 'all') return messages;
    return messages.filter(m => m.type === filter);
  }, [messages, filter]);
  
  // 发送消息
  const sendMessage = useCallback(() => {
    if (inputText.trim()) {
      setMessages(prev => [
        ...prev,
        {
          id: Date.now(),
          text: inputText,
          timestamp: Date.now(),
          type: 'sent'
        }
      ]);
      setInputText('');
    }
  }, [inputText]);
  
  // 删除消息
  const deleteMessage = useCallback((id) => {
    setMessages(prev => prev.filter(m => m.id !== id));
  }, []);
  
  return (
    <div className="chat-app">
      <MessageFilter filter={filter} onFilterChange={setFilter} />
      
      <MemoMessageList
        messages={filteredMessages}
        onDelete={deleteMessage}
      />
      
      <MemoMessageInput
        value={inputText}
        onChange={setInputText}
        onSend={sendMessage}
      />
    </div>
  );
}

const MemoMessageList = React.memo(function MessageList({ messages, onDelete }) {
  console.log('MessageList渲染');
  
  return (
    <div className="message-list">
      {messages.map(message => (
        <MemoMessage
          key={message.id}
          message={message}
          onDelete={onDelete}
        />
      ))}
    </div>
  );
});

const MemoMessage = React.memo(function Message({ message, onDelete }) {
  console.log('Message渲染:', message.id);
  
  const handleDelete = useCallback(() => {
    onDelete(message.id);
  }, [message.id, onDelete]);
  
  return (
    <div className={`message ${message.type}`}>
      <p>{message.text}</p>
      <span className="timestamp">
        {new Date(message.timestamp).toLocaleTimeString()}
      </span>
      <button onClick={handleDelete}>删除</button>
    </div>
  );
});

const MemoMessageInput = React.memo(function MessageInput({ value, onChange, onSend }) {
  console.log('MessageInput渲染');
  
  const handleKeyPress = (e) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      onSend();
    }
  };
  
  return (
    <div className="message-input">
      <input
        value={value}
        onChange={e => onChange(e.target.value)}
        onKeyPress={handleKeyPress}
        placeholder="输入消息..."
      />
      <button onClick={onSend}>发送</button>
    </div>
  );
});

第四部分:性能优化检查清单

4.1 检查项目

jsx
// 性能优化检查清单
const PerformanceChecklist = {
  // 1. State管理
  stateManagement: {
    question: '是否合理拆分State?',
    bad: '一个大State对象',
    good: '多个小State'
  },
  
  // 2. 计算缓存
  memoization: {
    question: '是否缓存昂贵的计算?',
    bad: '每次渲染都重新计算',
    good: '使用useMemo缓存'
  },
  
  // 3. 函数缓存
  callbackMemo: {
    question: '传给子组件的函数是否缓存?',
    bad: '内联函数或每次创建新函数',
    good: '使用useCallback缓存'
  },
  
  // 4. 组件缓存
  componentMemo: {
    question: '渲染成本高的组件是否使用memo?',
    bad: '普通组件',
    good: '使用React.memo'
  },
  
  // 5. 列表渲染
  listRendering: {
    question: '列表是否使用正确的key?',
    bad: '使用index作为key',
    good: '使用唯一稳定的id'
  },
  
  // 6. 条件渲染
  conditionalRendering: {
    question: '是否避免不必要的渲染?',
    bad: '渲染后再隐藏',
    good: '条件渲染或懒加载'
  }
};

4.2 性能审计工具

jsx
function PerformanceAudit() {
  const [issues, setIssues] = useState([]);
  
  const checkComponent = (component) => {
    const newIssues = [];
    
    // 检查1:是否有大列表没有使用memo
    if (component.hasLargeList && !component.usesM么) {
      newIssues.push({
        severity: 'high',
        message: '大列表未使用React.memo优化'
      });
    }
    
    // 检查2:是否有内联函数传给子组件
    if (component.hasInlineFunctions) {
      newIssues.push({
        severity: 'medium',
        message: '使用内联函数,考虑useCallback'
      });
    }
    
    // 检查3:是否有昂贵的计算没有缓存
    if (component.hasExpensiveCalculation && !component.usesMemo) {
      newIssues.push({
        severity: 'high',
        message: '昂贵的计算未使用useMemo缓存'
      });
    }
    
    setIssues(newIssues);
  };
  
  return (
    <div>
      <h2>性能审计报告</h2>
      <ul>
        {issues.map((issue, i) => (
          <li key={i} className={`issue-${issue.severity}`}>
            [{issue.severity}] {issue.message}
          </li>
        ))}
      </ul>
    </div>
  );
}

第五部分:优化前后对比数据

5.1 渲染次数对比

jsx
function RenderCountComparison() {
  const [count, setCount] = useState(0);
  const [items] = useState(Array(100).fill(0).map((_, i) => ({
    id: i,
    name: `Item ${i}`
  })));
  
  // 记录渲染次数
  const unoptimizedCount = useRef(0);
  const optimizedCount = useRef(0);
  
  const handleClick = useCallback(() => {
    console.log('点击');
  }, []);
  
  return (
    <div>
      <button onClick={() => setCount(c => c + 1)}>
        更新: {count}
      </button>
      
      <div style={{ display: 'flex', gap: '20px' }}>
        <div>
          <h3>未优化版本</h3>
          <p>渲染次数: {unoptimizedCount.current}</p>
          {items.map(item => (
            <UnoptimizedItem
              key={item.id}
              item={item}
              onClick={handleClick}
              renderCount={unoptimizedCount}
            />
          ))}
        </div>
        
        <div>
          <h3>优化版本</h3>
          <p>渲染次数: {optimizedCount.current}</p>
          {items.map(item => (
            <OptimizedItem
              key={item.id}
              item={item}
              onClick={handleClick}
              renderCount={optimizedCount}
            />
          ))}
        </div>
      </div>
    </div>
  );
}

function UnoptimizedItem({ item, onClick, renderCount }) {
  renderCount.current++;
  return (
    <div onClick={() => onClick(item.id)}>
      {item.name}
    </div>
  );
}

const OptimizedItem = React.memo(function OptimizedItem({ item, onClick, renderCount }) {
  renderCount.current++;
  return (
    <div onClick={() => onClick(item.id)}>
      {item.name}
    </div>
  );
});

5.2 内存使用对比

jsx
function MemoryComparison() {
  const [showDemo, setShowDemo] = useState(false);
  
  useEffect(() => {
    if (showDemo && performance.memory) {
      console.log('内存使用:', {
        usedJSHeapSize: (performance.memory.usedJSHeapSize / 1048576).toFixed(2) + 'MB',
        totalJSHeapSize: (performance.memory.totalJSHeapSize / 1048576).toFixed(2) + 'MB',
        jsHeapSizeLimit: (performance.memory.jsHeapSizeLimit / 1048576).toFixed(2) + 'MB'
      });
    }
  }, [showDemo]);
  
  return (
    <div>
      <button onClick={() => setShowDemo(!showDemo)}>
        切换演示
      </button>
      
      {showDemo && <HeavyComponent />}
    </div>
  );
}

第六部分:React 19自动优化

6.1 React Compiler

jsx
// React 19编译器自动优化
function AutoOptimizedByCompiler({ items }) {
  // 编译器会自动识别并优化这些模式
  
  // 自动添加useMemo
  const filtered = items.filter(item => item.active);
  
  // 自动添加useCallback
  const handleClick = () => {
    console.log('click');
  };
  
  // 自动添加React.memo
  return (
    <div>
      {filtered.map(item => (
        <Item key={item.id} item={item} onClick={handleClick} />
      ))}
    </div>
  );
}

// 编译后可能变成:
function CompiledVersion({ items }) {
  const filtered = useMemo(() =>
    items.filter(item => item.active),
    [items]
  );
  
  const handleClick = useCallback(() => {
    console.log('click');
  }, []);
  
  return (
    <div>
      {filtered.map(item => (
        <MemoItem key={item.id} item={item} onClick={handleClick} />
      ))}
    </div>
  );
}

const MemoItem = React.memo(Item);

6.2 编译器优化指南

jsx
// 编译器友好的代码模式
function CompilerFriendly() {
  // ✅ 好:清晰的数据流
  const data = props.data;
  const filtered = data.filter(x => x.active);
  const mapped = filtered.map(x => x.value);
  
  // ❌ 避免:复杂的嵌套逻辑
  const complex = props.data
    .filter(x => x.active && someCondition(x))
    .map(x => {
      if (x.type === 'A') return transformA(x);
      if (x.type === 'B') return transformB(x);
      return x;
    });
}

第七部分:最佳实践总结

7.1 优化决策树

jsx
// 决策树:是否需要优化?
function shouldOptimize(component) {
  // 1. 组件是否渲染频繁?
  if (!component.rendersFrequently) {
    return false;  // 不需要优化
  }
  
  // 2. 组件渲染成本是否高?
  if (!component.isExpensiveToRender) {
    return false;  // 不需要优化
  }
  
  // 3. Props是否经常相同?
  if (!component.propsOftenSame) {
    return false;  // memo无效,不需要
  }
  
  // 满足以上条件,值得优化
  return true;
}

// 应用示例
function OptimizationExample() {
  // 场景1:高频更新的简单组件 - 不需要优化
  function Clock() {
    const [time, setTime] = useState(Date.now());
    useEffect(() => {
      const timer = setInterval(() => setTime(Date.now()), 1000);
      return () => clearInterval(timer);
    }, []);
    return <div>{new Date(time).toLocaleTimeString()}</div>;
  }
  
  // 场景2:低频更新的复杂组件 - 不需要优化
  function RarelyUpdated({ data }) {
    // 一天才更新一次
    return <ComplexChart data={data} />;
  }
  
  // 场景3:高频更新、高成本、props稳定 - 需要优化
  const OptimizedListItem = React.memo(function ListItem({ item, onAction }) {
    // 复杂的渲染逻辑
    return <ExpensiveView item={item} onAction={onAction} />;
  });
}

7.2 优化优先级

jsx
// 优化优先级(从高到低)
const OptimizationPriorities = [
  {
    priority: 1,
    name: '避免不必要的State',
    example: '使用派生状态代替重复State'
  },
  {
    priority: 2,
    name: '正确使用key',
    example: '使用稳定唯一的key'
  },
  {
    priority: 3,
    name: '组件懒加载',
    example: '使用React.lazy和Suspense'
  },
  {
    priority: 4,
    name: '虚拟化长列表',
    example: '使用react-window'
  },
  {
    priority: 5,
    name: '使用memo系列Hook',
    example: 'useMemo, useCallback, React.memo'
  }
];

练习题

基础练习

  1. 对比一个列表组件优化前后的渲染次数
  2. 使用Profiler测量组件渲染时间
  3. 找出一个组件的性能瓶颈并优化

进阶练习

  1. 优化一个包含500个项目的商品列表
  2. 实现一个性能监控组件,显示实时渲染统计
  3. 创建一个性能对比工具,对比优化前后的差异

高级练习

  1. 优化一个复杂的数据仪表板应用
  2. 实现一个聊天应用,支持1000+条消息的高性能渲染
  3. 分析React 19编译器的优化效果

通过本章学习,你已经全面掌握了React性能优化的各种技术。合理使用这些优化手段,可以让你的应用运行如飞!记住:不要过早优化,先测量再优化。继续学习,成为React性能大师!