性能优化实战:用Claude Code把React应用提速3-5倍
这个案例用Claude Code优化一个真实的React电商应用。问题很明显:页面慢、渲染卡、内存高。看完你会知道怎么系统化诊断和解决性能问题。
问题有多严重
某电商平台前端性能烂到用户投诉:
用户反馈
- 首页加载8-12秒
- 商品列表滚动卡顿
- 搜索反应慢
- 标签页经常崩
Lighthouse评分
Performance: 32/100 # 红色警告
First Contentful Paint: 4.2s
Largest Contentful Paint: 8.7s
Time to Interactive: 12.3s
Total Blocking Time: 1,850ms
Cumulative Layout Shift: 0.25
# 内存问题
JS Heap: 145MB(持续增长)
DOM Nodes: 12,000+
Event Listeners: 850+
项目结构
ecommerce-app/
├── src/
│ ├── components/
│ │ ├── ProductList.tsx # 商品列表(主要问题源)
│ │ ├── ProductCard.tsx # 商品卡片
│ │ ├── SearchBar.tsx # 搜索栏
│ │ ├── FilterSidebar.tsx # 筛选侧边栏
│ │ └── Header.tsx # 页头
│ ├── pages/
│ │ ├── Home.tsx # 首页
│ │ ├── ProductDetail.tsx # 商品详情
│ │ └── Cart.tsx # 购物车
│ ├── hooks/
│ │ ├── useProducts.ts # 商品数据Hook
│ │ └── useSearch.ts # 搜索Hook
│ ├── api/
│ │ └── products.ts # API调用
│ ├── utils/
│ │ └── formatters.ts # 格式化工具
│ └── App.tsx
├── package.json
└── tsconfig.json
技术栈
React 18.2.0 + TypeScript 5.0 + Redux Toolkit + React Router v6 + Axios
第一阶段:性能分析
启动Claude Code
cd ecommerce-app
claude
Claude Code启动了。
第一轮对话
你: 我有个React电商应用需要性能优化。先帮我分析项目结构,找出性能瓶颈。
具体做:
1. 读主要组件文件
2. 分析性能问题
3. 生成报告
Claude Code开始分析:
📁 Reading project files...
✓ Read package.json
✓ Read src/App.tsx
✓ Read src/components/ProductList.tsx
✓ Read src/components/ProductCard.tsx
✓ Read src/hooks/useProducts.ts
分析性能问题...
代码性能分析
ProductList.tsx初始代码(有问题):
import React, { useState, useEffect } from 'react';
import { useProducts } from '../hooks/useProducts';
import { ProductCard } from './ProductCard';
import '../styles/ProductList.css';
interface ProductListProps {
category?: string;
searchQuery?: string;
}
export const ProductList: React.FC<ProductListProps> = ({
category,
searchQuery,
}) => {
const [products, setProducts] = useState<Product[]>([]);
const [filteredProducts, setFilteredProducts] = useState<Product[]>([]);
const [sortBy, setSortBy] = useState<'name' | 'price' | 'rating'>('name');
// 每次渲染都重新获取数据
useEffect(() => {
const fetchProducts = async () => {
const response = await fetch('/api/products');
const data = await response.json();
setProducts(data);
};
fetchProducts();
}, []); // 缺少category依赖
// 每次渲染都进行过滤和排序(性能杀手)
const filtered = products
.filter(p => !category || p.category === category)
.filter(p => !searchQuery || p.name.toLowerCase().includes(searchQuery.toLowerCase()))
.filter(p => p.price > 0)
.sort((a, b) => {
if (sortBy === 'price') return a.price - b.price;
if (sortBy === 'rating') return b.rating - a.rating;
return a.name.localeCompare(b.name);
});
// 不必要的重新计算
useEffect(() => {
setFilteredProducts(filtered);
}, [filtered]);
// 没有虚拟化,渲染所有商品
return (
<div className="product-list">
<select value={sortBy} onChange={(e) => setSortBy(e.target.value as any)}>
<option value="name">按名称</option>
<option value="price">按价格</option>
<option value="rating">按评分</option>
</select>
<div className="products-grid">
{filteredProducts.map(product => (
<ProductCard
key={product.id}
product={product}
onAddToCart={() => console.log('Add to cart', product.id)}
/>
))}
</div>
</div>
);
};
ProductCard.tsx初始代码:
import React from 'react';
import { Product } from '../types';
interface ProductCardProps {
product: Product;
onAddToCart: () => void;
}
export const ProductCard: React.FC<ProductCardProps> = ({ product, onAddToCart }) => {
// 每次渲染都创建新函数
const handleMouseEnter = () => {
console.log('Hover', product.id);
};
// 每次渲染都进行复杂的计算
const discountPrice = (() => {
const basePrice = product.price;
const discount = product.discount || 0;
const tax = basePrice * 0.1;
const shipping = basePrice > 100 ? 0 : 10;
return basePrice * (1 - discount / 100) + tax + shipping;
})();
// 没有使用React.memo,父组件更新时总是重新渲染
return (
<div className="product-card" onMouseEnter={handleMouseEnter}>
<img src={product.image} alt={product.name} />
<h3>{product.name}</h3>
<p className="price">${discountPrice.toFixed(2)}</p>
<p className="original-price">${product.price}</p>
<button onClick={onAddToCart}>添加到购物车</button>
</div>
);
};
useProducts.ts初始代码:
import { useState, useEffect } from 'react';
import { Product } from '../types';
export const useProducts = (category?: string) => {
const [products, setProducts] = useState<Product[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
const fetchProducts = async () => {
setLoading(true);
try {
// 没有缓存,每次都重新请求
const response = await fetch(`/api/products?category=${category || ''}`);
const data = await response.json();
setProducts(data);
} catch (err) {
setError('Failed to fetch products');
} finally {
setLoading(false);
}
};
fetchProducts();
}, [category]); // category改变时重新请求
return { products, loading, error };
};
Claude Code生成的性能分析报告
## 性能分析报告
### 🔴 严重问题 (Critical Issues)
#### 1. ProductList组件 - 过度渲染
**问题**: 每次父组件更新都会重新渲染整个商品列表
**影响**: 1000+商品时,每次更新渲染1000+组件,耗时2-3秒
**位置**: `src/components/ProductList.tsx:15-60`
**具体问题:**
- useEffect依赖不完整,导致重复数据获取
- 每次渲染都进行过滤和排序操作
- 没有使用useMemo缓存计算结果
- 没有虚拟化长列表
#### 2. ProductCard组件 - 避免不必要的重新渲染
**问题**: 未使用React.memo,父组件更新时所有卡片都重新渲染
**影响**: 单次更新可能触发数百次不必要的组件渲染
**位置**: `src/components/ProductCard.tsx:8-35`
**具体问题:**
- 缺少React.memo包装
- 每次渲染创建新的事件处理函数
- 每次渲染重新计算折扣价格
- 图片未懒加载
#### 3. 价格计算 - 重复计算
**问题**: 每次渲染都执行复杂的折扣计算
**影响**: 增加渲染时间15-20ms/组件
**位置**: `src/components/ProductCard.tsx:15-22`
#### 4. 数据获取 - 缺少缓存
**问题**: 每次category变化都重新请求,无缓存机制
**影响**: 不必要的网络请求,增加加载时间
**位置**: `src/hooks/useProducts.ts:8-25`
### 🟡 中等问题 (Medium Issues)
#### 5. SearchBar组件 - 防抖缺失
**问题**: 每次按键都触发搜索请求
**影响**: 大量不必要的API调用
**建议**: 添加300ms防抖
#### 6. 状态管理 - Redux过度使用
**问题**: 简单状态使用Redux,增加复杂度
**影响**: 不必要的reducer调用和状态更新
**建议**: 使用React Context或useState
#### 7. 图片优化 - 未压缩和懒加载
**问题**: 所有图片立即加载,未优化
**影响**: 首屏加载时间增加3-5秒
**建议**: 使用WebP格式 + 懒加载
### 🟢 轻微问题 (Minor Issues)
#### 8. 代码分割 - 未实现
**影响**: 初始JS bundle过大(800KB)
**建议**: 使用React.lazy和Suspense
#### 9. CSS - 未优化
**影响**: 大量未使用的CSS样式
**建议**: CSS Tree Shaking
### 性能评分
| 指标 | 当前 | 目标 | 状态 |
|------|------|------|------|
| Lighthouse性能 | 32 | 90+ | 🔴 |
| 首次内容绘制 | 4.2s | <1.5s | 🔴 |
| 最大内容绘制 | 8.7s | <2.5s | 🔴 |
| 首次输入延迟 | 12.3s | <3s | 🔴 |
| 总阻塞时间 | 1,850ms | <300ms | 🔴 |
### 优化优先级
**Phase 1 - 紧急(预期提升60%性能)**
1. ✅ 修复ProductList过度渲染
2. ✅ 实现ProductCard.memo
3. ✅ 添加列表虚拟化
4. ✅ 优化价格计算
**Phase 2 - 重要(额外提升25%性能)**
5. ✅ 实现数据缓存
6. ✅ 添加搜索防抖
7. ✅ 图片懒加载和优化
**Phase 3 - 增强(额外提升15%性能)**
8. ✅ 代码分割
9. ✅ 优化CSS
10. ✅ Service Worker缓存
预期总体性能提升: **300-500%**
第二阶段:实施核心优化
优化1: 修复ProductList组件
你: 开始实施Phase 1优化。首先重构ProductList组件:
要求:
1. 使用useMemo缓存过滤和排序结果
2. 使用useCallback缓存事件处理函数
3. 修复useEffect依赖
4. 添加loading和error状态处理
5. 保持组件功能不变
只修改src/components/ProductList.tsx
Claude Code生成的优化代码:
import React, { useState, useEffect, useMemo, useCallback } from 'react';
import { useProducts } from '../hooks/useProducts';
import { ProductCard } from './ProductCard';
import { Product } from '../types';
import '../styles/ProductList.css';
interface ProductListProps {
category?: string;
searchQuery?: string;
}
export const ProductList: React.FC<ProductListProps> = ({
category,
searchQuery,
}) => {
// 使用自定义Hook获取数据
const { products, loading, error, refetch } = useProducts(category);
const [sortBy, setSortBy] = useState<'name' | 'price' | 'rating'>('name');
// 使用useMemo缓存过滤和排序结果
const filteredProducts = useMemo(() => {
let result = products;
// 过滤
if (category) {
result = result.filter(p => p.category === category);
}
if (searchQuery) {
const query = searchQuery.toLowerCase();
result = result.filter(p =>
p.name.toLowerCase().includes(query)
);
}
// 过滤掉无效商品
result = result.filter(p => p.price > 0);
// 排序
const sorted = [...result].sort((a, b) => {
if (sortBy === 'price') return a.price - b.price;
if (sortBy === 'rating') return b.rating - a.rating;
return a.name.localeCompare(b.name);
});
return sorted;
}, [products, category, searchQuery, sortBy]);
// 使用useCallback缓存事件处理函数
const handleSortChange = useCallback((e: React.ChangeEvent<HTMLSelectElement>) => {
setSortBy(e.target.value as 'name' | 'price' | 'rating');
}, []);
const handleAddToCart = useCallback((productId: string) => {
console.log('Add to cart', productId);
// TODO: 实现添加到购物车逻辑
}, []);
// 加载状态
if (loading) {
return (
<div className="product-list loading">
<div className="spinner" />
<p>加载商品中...</p>
</div>
);
}
// 错误状态
if (error) {
return (
<div className="product-list error">
<p>加载失败: {error}</p>
<button onClick={refetch}>重试</button>
</div>
);
}
// 空状态
if (filteredProducts.length === 0) {
return (
<div className="product-list empty">
<p>未找到符合条件的商品</p>
</div>
);
}
return (
<div className="product-list">
<div className="product-list-header">
<h2>商品列表 ({filteredProducts.length}件)</h2>
<select value={sortBy} onChange={handleSortChange} className="sort-select">
<option value="name">按名称排序</option>
<option value="price">按价格排序</option>
<option value="rating">按评分排序</option>
</select>
</div>
<div className="products-grid">
{filteredProducts.map(product => (
<ProductCard
key={product.id}
product={product}
onAddToCart={handleAddToCart}
/>
))}
</div>
</div>
);
};
优化效果:
- 渲染时间: 2,300ms → 180ms (减少92%)
- 内存使用: 减少65%
- 感觉流畅度: 显著提升
优化2: 实现ProductCard.memo
你: 优化ProductCard组件:
要求:
1. 使用React.memo包装组件
2. 使用useMemo缓存价格计算
3. 使用useCallback缓存事件处理函数
4. 添加图片懒加载
5. 实现shouldComponentUpdate优化逻辑
只修改src/components/ProductCard.tsx
优化后的ProductCard.tsx:
import React, { useMemo, useCallback, useState } from 'react';
import { Product } from '../types';
import '../styles/ProductCard.css';
interface ProductCardProps {
product: Product;
onAddToCart: (productId: string) => void;
}
// 使用React.memo避免不必要的重新渲染
export const ProductCard = React.memo<ProductCardProps>(({ product, onAddToCart }) => {
const [imageLoaded, setImageLoaded] = useState(false);
const [isHovered, setIsHovered] = useState(false);
// 使用useMemo缓存价格计算
const discountPrice = useMemo(() => {
const basePrice = product.price;
const discount = product.discount || 0;
const tax = basePrice * 0.1;
const shipping = basePrice > 100 ? 0 : 10;
return basePrice * (1 - discount / 100) + tax + shipping;
}, [product.price, product.discount]);
const savings = useMemo(() => {
return product.price - discountPrice;
}, [product.price, discountPrice]);
// 使用useCallback缓存事件处理函数
const handleMouseEnter = useCallback(() => {
setIsHovered(true);
}, []);
const handleMouseLeave = useCallback(() => {
setIsHovered(false);
}, []);
const handleImageLoad = useCallback(() => {
setImageLoaded(true);
}, []);
const handleClick = useCallback(() => {
onAddToCart(product.id);
}, [product.id, onAddToCart]);
return (
<div
className={`product-card ${isHovered ? 'hovered' : ''} ${imageLoaded ? 'loaded' : 'loading'}`}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
>
<div className="product-image">
{!imageLoaded && <div className="image-placeholder" />}
<img
src={product.image}
alt={product.name}
loading="lazy"
onLoad={handleImageLoad}
style={{ opacity: imageLoaded ? 1 : 0 }}
/>
{savings > 0 && (
<span className="discount-badge">-{product.discount}%</span>
)}
</div>
<div className="product-info">
<h3 className="product-name">{product.name}</h3>
<p className="product-category">{product.category}</p>
<div className="product-rating">
<span className="stars">{'★'.repeat(Math.floor(product.rating))}</span>
<span className="rating-value">{product.rating.toFixed(1)}</span>
</div>
<div className="product-price">
<span className="current-price">${discountPrice.toFixed(2)}</span>
{savings > 0 && (
<span className="original-price">${product.price.toFixed(2)}</span>
)}
</div>
<button
className="add-to-cart-button"
onClick={handleClick}
disabled={!imageLoaded}
>
添加到购物车
</button>
</div>
</div>
);
}, (prevProps, nextProps) => {
// 自定义比较函数,只在product或onAddToCart真正改变时重新渲染
return (
prevProps.product.id === nextProps.product.id &&
prevProps.product.price === nextProps.product.price &&
prevProps.product.discount === nextProps.product.discount &&
prevProps.product.name === nextProps.product.name &&
prevProps.onAddToCart === nextProps.onAddToCart
);
});
ProductCard.displayName = 'ProductCard';
优化效果:
- 单个卡片渲染时间: 45ms → 8ms (减少82%)
- 列表滚动FPS: 15fps → 55fps (提升267%)
- 不必要的重新渲染: 减少95%
优化3: 添加列表虚拟化
你: 为ProductList实现虚拟滚动:
要求:
1. 使用react-window库实现虚拟化
2. 只渲染可见区域+缓冲区的商品
3. 保持滚动位置和性能
4. 处理动态高度的情况
5. 创建VariableSizeList组件
安装必要的依赖并实现虚拟化
Claude Code自动安装依赖并创建虚拟化组件:
npm install react-window
npm install -D @types/react-window
创建VirtualProductList.tsx:
import React, { useRef, useEffect } from 'react';
import { VariableSizeList as List } from 'react-window';
import { ProductCard } from './ProductCard';
import { Product } from '../types';
import '../styles/VirtualProductList.css';
interface VirtualProductListProps {
products: Product[];
onAddToCart: (productId: string) => void;
height: number;
itemHeight: number;
}
export const VirtualProductList: React.FC<VirtualProductListProps> = ({
products,
onAddToCart,
height,
itemHeight = 350,
}) => {
const listRef = useRef<List>(null);
// 获取单个项目的高度
const getItemSize = (index: number) => {
// 可以根据不同商品返回不同高度
return itemHeight;
};
// 渲染单个商品
const Row = ({ index, style }: { index: number; style: React.CSSProperties }) => {
const product = products[index];
return (
<div style={style} className="virtual-list-item">
<ProductCard
product={product}
onAddToCart={onAddToCart}
/>
</div>
);
};
// 当products数量变化时,重新计算列表大小
useEffect(() => {
if (listRef.current) {
listRef.current.resetAfterIndex(0);
}
}, [products.length]);
// 空状态
if (products.length === 0) {
return (
<div className="virtual-list-empty">
<p>暂无商品</p>
</div>
);
}
return (
<div className="virtual-product-list">
<List
ref={listRef}
height={height}
itemCount={products.length}
itemSize={getItemSize}
width="100%"
overscanCount={5} // 预渲染5个项目提升流畅度
>
{Row}
</List>
</div>
);
};
更新ProductList使用虚拟化:
import React, { useState, useMemo, useCallback, useEffect } from 'react';
import { useProducts } from '../hooks/useProducts';
import { VirtualProductList } from './VirtualProductList';
import { Product } from '../types';
import '../styles/ProductList.css';
export const ProductList: React.FC<ProductListProps> = ({
category,
searchQuery,
}) => {
const { products, loading, error, refetch } = useProducts(category);
const [sortBy, setSortBy] = useState<'name' | 'price' | 'rating'>('name');
const [containerHeight, setContainerHeight] = useState(600);
// 计算容器高度
useEffect(() => {
const updateHeight = () => {
const height = window.innerHeight - 200; // 减去header和padding
setContainerHeight(height);
};
updateHeight();
window.addEventListener('resize', updateHeight);
return () => window.removeEventListener('resize', updateHeight);
}, []);
// 使用useMemo缓存过滤和排序结果
const filteredProducts = useMemo(() => {
// ... (同上)
}, [products, category, searchQuery, sortBy]);
const handleSortChange = useCallback((e: React.ChangeEvent<HTMLSelectElement>) => {
setSortBy(e.target.value as 'name' | 'price' | 'rating');
}, []);
const handleAddToCart = useCallback((productId: string) => {
console.log('Add to cart', productId);
}, []);
if (loading) {
return <div className="loading">加载中...</div>;
}
if (error) {
return <div className="error">{error}</div>;
}
return (
<div className="product-list">
<div className="product-list-header">
<h2>商品列表 ({filteredProducts.length}件)</h2>
<select value={sortBy} onChange={handleSortChange}>
<option value="name">按名称</option>
<option value="price">按价格</option>
<option value="rating">按评分</option>
</select>
</div>
<VirtualProductList
products={filteredProducts}
onAddToCart={handleAddToCart}
height={containerHeight}
itemHeight={350}
/>
</div>
);
};
虚拟化效果:
- 1000件商品DOM节点: 1000 → 20 (减少98%)
- 初始渲染时间: 2,300ms → 85ms (减少96%)
- 内存占用: 145MB → 35MB (减少76%)
- 滚动性能: 15fps → 60fps (提升300%)
优化4: 优化数据获取和缓存
你: 优化useProducts Hook,实现数据缓存:
要求:
1. 添加localStorage缓存
2. 实现缓存失效策略(5分钟)
3. 添加请求去重
4. 实现乐观更新
5. 添加错误重试机制
更新src/hooks/useProducts.ts
优化后的useProducts.ts:
import { useState, useEffect, useCallback, useRef } from 'react';
import { Product } from '../types';
const CACHE_DURATION = 5 * 60 * 1000; // 5分钟
const CACHE_PREFIX = 'products_cache_';
interface CacheData {
products: Product[];
timestamp: number;
}
interface UseProductsOptions {
enableCache?: boolean;
staleTime?: number;
retryCount?: number;
}
export const useProducts = (
category?: string,
options: UseProductsOptions = {}
) => {
const {
enableCache = true,
staleTime = CACHE_DURATION,
retryCount = 3,
} = options;
const [products, setProducts] = useState<Product[]>([]);
const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
const abortControllerRef = useRef<AbortController | null>(null);
const retryCountRef = useRef(0);
// 从缓存读取
const getFromCache = useCallback((key: string): Product[] | null => {
if (!enableCache) return null;
try {
const cached = localStorage.getItem(`${CACHE_PREFIX}${key}`);
if (!cached) return null;
const data: CacheData = JSON.parse(cached);
const isExpired = Date.now() - data.timestamp > staleTime;
if (isExpired) {
localStorage.removeItem(`${CACHE_PREFIX}${key}`);
return null;
}
return data.products;
} catch {
return null;
}
}, [enableCache, staleTime]);
// 保存到缓存
const saveToCache = useCallback((key: string, data: Product[]) => {
if (!enableCache) return;
try {
const cacheData: CacheData = {
products: data,
timestamp: Date.now(),
};
localStorage.setItem(`${CACHE_PREFIX}${key}`, JSON.stringify(cacheData));
} catch (err) {
console.warn('Failed to save to cache:', err);
}
}, [enableCache]);
// 获取产品数据
const fetchProducts = useCallback(async (shouldRetry: boolean = false) => {
// 取消之前的请求
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
const cacheKey = category || 'all';
// 先尝试从缓存读取
const cachedProducts = getFromCache(cacheKey);
if (cachedProducts && !shouldRetry) {
setProducts(cachedProducts);
setLoading(false);
return;
}
// 创建新的AbortController
abortControllerRef.current = new AbortController();
setLoading(true);
setError(null);
try {
const response = await fetch(`/api/products?category=${category || ''}`, {
signal: abortControllerRef.current.signal,
});
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data: Product[] = await response.json();
setProducts(data);
saveToCache(cacheKey, data);
retryCountRef.current = 0; // 重置重试计数
} catch (err) {
if (err instanceof Error && err.name === 'AbortError') {
return; // 请求被取消,不处理
}
const errorMessage = err instanceof Error ? err.message : 'Unknown error';
// 重试逻辑
if (retryCountRef.current < retryCount) {
retryCountRef.current++;
console.log(`Retrying... (${retryCountRef.current}/${retryCount})`);
setTimeout(() => fetchProducts(true), 1000 * retryCountRef.current);
return;
}
setError(errorMessage);
} finally {
setLoading(false);
}
}, [category, getFromCache, saveToCache, retryCount]);
// 手动刷新
const refetch = useCallback(() => {
const cacheKey = category || 'all';
localStorage.removeItem(`${CACHE_PREFIX}${cacheKey}`);
fetchProducts(true);
}, [category, fetchProducts]);
// 乐观更新
const updateProduct = useCallback((productId: string, updates: Partial<Product>) => {
setProducts(prev =>
prev.map(p =>
p.id === productId ? { ...p, ...updates } : p
)
);
}, []);
// 删除产品
const removeProduct = useCallback((productId: string) => {
setProducts(prev => prev.filter(p => p.id !== productId));
}, []);
// 初始加载
useEffect(() => {
fetchProducts();
}, [fetchProducts]);
// 清理
useEffect(() => {
return () => {
if (abortControllerRef.current) {
abortControllerRef.current.abort();
}
};
}, []);
return {
products,
loading,
error,
refetch,
updateProduct,
removeProduct,
};
};
缓存效果:
- 重复访问加载时间: 2,300ms → 45ms (减少98%)
- API请求减少: 75%
- 离线体验: 显著提升
第三阶段:内存泄漏检测和修复
使用React DevTools Profiler
你: 帮我检测和修复内存泄漏:
要做的事情:
1. 检查所有组件的useEffect清理
2. 确保所有订阅正确取消
3. 检查事件监听器是否移除
4. 优化定时器使用
5. 修复任何潜在的内存泄漏
重点检查:
- src/components/ProductList.tsx
- src/hooks/useProducts.ts
- src/hooks/useSearch.ts
- src/components/SearchBar.tsx
内存泄漏诊断
问题1: SearchBar组件 - 未取消的定时器
// ❌ 有问题的代码
export const SearchBar: React.FC = () => {
const [query, setQuery] = useState('');
useEffect(() => {
const timer = setTimeout(() => {
// 执行搜索
}, 300);
// 忘记清理定时器!
}, [query]);
return <input value={query} onChange={e => setQuery(e.target.value)} />;
};
✅ 修复后的代码:
export const SearchBar: React.FC = () => {
const [query, setQuery] = useState('');
useEffect(() => {
const timer = setTimeout(() => {
// 执行搜索
performSearch(query);
}, 300);
// 清理定时器
return () => clearTimeout(timer);
}, [query]);
return <input value={query} onChange={e => setQuery(e.target.value)} />;
};
问题2: FilterSidebar - 未移除的事件监听器
// ❌ 有问题的代码
export const FilterSidebar: React.FC = () => {
useEffect(() => {
const handleResize = () => {
// 处理窗口大小改变
};
window.addEventListener('resize', handleResize);
// 忘记移除监听器!
}, []);
return <div>Filters</div>;
};
✅ 修复后的代码:
export const FilterSidebar: React.FC = () => {
useEffect(() => {
const handleResize = () => {
// 处理窗口大小改变
};
window.addEventListener('resize', handleResize);
// 清理函数
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return <div>Filters</div>;
};
问题3: WebSocket连接 - 未正确关闭
// ❌ 有问题的代码
export const useWebSocket = (url: string) => {
const [socket, setSocket] = useState<WebSocket | null>(null);
useEffect(() => {
const ws = new WebSocket(url);
setSocket(ws);
// 忘记关闭连接!
}, [url]);
return socket;
};
✅ 修复后的代码:
export const useWebSocket = (url: string) => {
const [socket, setSocket] = useState<WebSocket | null>(null);
useEffect(() => {
const ws = new WebSocket(url);
setSocket(ws);
// 清理函数
return () => {
if (ws.readyState === WebSocket.OPEN) {
ws.close();
}
};
}, [url]);
return socket;
};
Claude Code生成的内存泄漏报告
## 内存泄漏检测报告
### 🔴 发现的内存泄漏
#### 1. SearchBar组件 - 定时器泄漏
**严重程度**: 高
**位置**: `src/components/SearchBar.tsx:15-22`
**问题**: setTimeout未清理,组件卸载后仍在执行
**影响**: 每次搜索泄漏约1KB内存
**修复**: ✓ 已添加清理函数
#### 2. FilterSidebar组件 - 事件监听器泄漏
**严重程度**: 高
**位置**: `src/components/FilterSidebar.tsx:28-35`
**问题**: resize事件监听器未移除
**影响**: 每次导航泄漏约2KB内存
**修复**: ✓ 已添加removeEventListener
#### 3. useProducts Hook - AbortController未清理
**严重程度**: 中
**位置**: `src/hooks/useProducts.ts:45-50`
**问题**: 组件卸载时未取消pending请求
**影响**: 可能导致状态更新已卸载的组件
**修复**: ✓ 已添加abort清理
#### 4. ProductDetail组件 - 订阅未取消
**严重程度**: 中
**位置**: `src/pages/ProductDetail.tsx:52-60`
**问题**: Redux订阅未取消
**影响**: 每次访问详情页泄漏约5KB内存
**修复**: ✓ 已添加unsubscribe
### 内存优化效果
| 场景 | 优化前 | 优化后 | 改善 |
|------|--------|--------|------|
| 浏览10个商品页 | +45MB | +5MB | 89% |
| 搜索10次 | +12MB | +2MB | 83% |
| 切换分类20次 | +38MB | +8MB | 79% |
| 长时间使用(1小时) | +350MB | +45MB | 87% |
### 验证方法
使用Chrome DevTools验证:
1. 打开DevTools → Memory
2. 录制Heap Snapshot
3. 执行操作(浏览、搜索、筛选)
4. 触发垃圾回收
5. 再次录制Heap Snapshot
6. 对比Detached DOM nodes
预期结果:
- Detached DOM: 0
- Memory trend: 平稳,无持续增长
第四阶段:性能监控和测试
实现性能监控
你: 创建性能监控系统:
要求:
1. 创建usePerformanceMonitor Hook
2. 监控关键指标(FP, FCP, LCP, FID, CLS)
3. 集成Web Vitals
4. 添加性能日志
5. 创建性能仪表板组件
创建新文件src/hooks/usePerformanceMonitor.ts
Claude Code创建性能监控系统:
npm install web-vitals
usePerformanceMonitor.ts:
import { useEffect, useState } from 'react';
import {
getCLS,
getFID,
getFCP,
getLCP,
getTTFB,
Metric,
ReportCallback,
} from 'web-vitals';
interface PerformanceMetrics {
cls: number | null;
fid: number | null;
fcp: number | null;
lcp: number | null;
ttfb: number | null;
}
interface PerformanceStats {
metrics: PerformanceMetrics;
score: 'good' | 'needs-improvement' | 'poor';
recommendations: string[];
}
export const usePerformanceMonitor = () => {
const [metrics, setMetrics] = useState<PerformanceMetrics>({
cls: null,
fid: null,
fcp: null,
lcp: null,
ttfb: null,
});
const [logs, setLogs] = useState<string[]>([]);
useEffect(() => {
const logMetric = (metric: Metric) => {
const logEntry = `${metric.name}: ${metric.value.toFixed(2)} ${getUnit(metric.name)}`;
setLogs(prev => [...prev, logEntry]);
// 发送到分析服务
if (process.env.NODE_ENV === 'production') {
sendToAnalytics(metric);
}
};
const reportCallback: ReportCallback = (metric) => {
logMetric(metric);
setMetrics(prev => ({
...prev,
[metric.name.toLowerCase()]: metric.value,
}));
};
// 测量所有Core Web Vitals
getCLS(reportCallback);
getFID(reportCallback);
getFCP(reportCallback);
getLCP(reportCallback);
getTTFB(reportCallback);
}, []);
// 计算性能分数
const getPerformanceScore = (): PerformanceStats['score'] => {
if (!metrics.lcp || !metrics.fid || !metrics.cls) {
return 'needs-improvement';
}
const scores = [
metrics.lcp < 2500 ? 1 : 0,
metrics.fid < 100 ? 1 : 0,
metrics.cls < 0.1 ? 1 : 0,
];
const totalScore = scores.reduce((sum, score) => sum + score, 0);
if (totalScore === 3) return 'good';
if (totalScore >= 1) return 'needs-improvement';
return 'poor';
};
// 生成优化建议
const getRecommendations = (): string[] => {
const recommendations: string[] = [];
if (metrics.lcp && metrics.lcp > 2500) {
recommendations.push('LCP过慢,建议优化图片加载和代码分割');
}
if (metrics.fid && metrics.fid > 100) {
recommendations.push('FID过长,建议减少JavaScript执行时间');
}
if (metrics.cls && metrics.cls > 0.1) {
recommendations.push('CLS过高,建议为图片和媒体设置尺寸');
}
if (metrics.fcp && metrics.fcp > 1800) {
recommendations.push('FCP过慢,建议减少渲染阻塞资源');
}
return recommendations;
};
// 获取单位
const getUnit = (metricName: string): string => {
if (metricName === 'CLS') return '';
return 'ms';
};
// 发送到分析服务
const sendToAnalytics = (metric: Metric) => {
// 实现发送到Google Analytics或其他服务
if (typeof gtag !== 'undefined') {
gtag('event', metric.name, {
value: metric.value,
event_category: 'Web Vitals',
event_label: metric.id,
non_interaction: true,
});
}
};
// 获取性能统计
const getStats = (): PerformanceStats => ({
metrics,
score: getPerformanceScore(),
recommendations: getRecommendations(),
});
return {
metrics,
logs,
getStats,
};
};
创建PerformanceDashboard组件:
import React from 'react';
import { usePerformanceMonitor } from '../hooks/usePerformanceMonitor';
import '../styles/PerformanceDashboard.css';
export const PerformanceDashboard: React.FC = () => {
const { metrics, getStats } = usePerformanceMonitor();
const stats = getStats();
const getScoreColor = (score: string) => {
switch (score) {
case 'good': return '#10b981';
case 'needs-improvement': return '#f59e0b';
case 'poor': return '#ef4444';
default: return '#6b7280';
}
};
const getMetricRating = (name: string, value: number | null): 'good' | 'warning' | 'poor' => {
if (value === null) return 'poor';
switch (name) {
case 'LCP':
if (value < 2500) return 'good';
if (value < 4000) return 'warning';
return 'poor';
case 'FID':
if (value < 100) return 'good';
if (value < 300) return 'warning';
return 'poor';
case 'CLS':
if (value < 0.1) return 'good';
if (value < 0.25) return 'warning';
return 'poor';
case 'FCP':
if (value < 1800) return 'good';
if (value < 3000) return 'warning';
return 'poor';
default:
return 'good';
}
};
return (
<div className="performance-dashboard">
<div className="dashboard-header">
<h2>性能监控面板</h2>
<div
className="overall-score"
style={{ backgroundColor: getScoreColor(stats.score) }}
>
{stats.score === 'good' && '✓ 优秀'}
{stats.score === 'needs-improvement' && '⚠ 需改进'}
{stats.score === 'poor' && '✗ 较差'}
</div>
</div>
<div className="metrics-grid">
<MetricCard
name="LCP"
value={metrics.lcp}
rating={getMetricRating('LCP', metrics.lcp)}
unit="ms"
threshold="< 2.5s"
/>
<MetricCard
name="FID"
value={metrics.fid}
rating={getMetricRating('FID', metrics.fid)}
unit="ms"
threshold="< 100ms"
/>
<MetricCard
name="CLS"
value={metrics.cls}
rating={getMetricRating('CLS', metrics.cls)}
unit=""
threshold="< 0.1"
/>
<MetricCard
name="FCP"
value={metrics.fcp}
rating={getMetricRating('FCP', metrics.fcp)}
unit="ms"
threshold="< 1.8s"
/>
<MetricCard
name="TTFB"
value={metrics.ttfb}
rating={getMetricRating('TTFB', metrics.ttfb)}
unit="ms"
threshold="< 800ms"
/>
</div>
{stats.recommendations.length > 0 && (
<div className="recommendations">
<h3>优化建议</h3>
<ul>
{stats.recommendations.map((rec, index) => (
<li key={index}>{rec}</li>
))}
</ul>
</div>
)}
</div>
);
};
interface MetricCardProps {
name: string;
value: number | null;
rating: 'good' | 'warning' | 'poor';
unit: string;
threshold: string;
}
const MetricCard: React.FC<MetricCardProps> = ({ name, value, rating, unit, threshold }) => {
const getRatingColor = () => {
switch (rating) {
case 'good': return '#10b981';
case 'warning': return '#f59e0b';
case 'poor': return '#ef4444';
}
};
return (
<div className="metric-card" style={{ borderColor: getRatingColor() }}>
<div className="metric-name">{name}</div>
<div className="metric-value">
{value !== null ? value.toFixed(2) : '-'}
<span className="metric-unit">{unit}</span>
</div>
<div className="metric-threshold">目标: {threshold}</div>
</div>
);
};
创建压力测试
你: 创建性能测试套件:
要求:
1. 使用Jest和React Testing Library
2. 渲染性能测试(大量数据)
3. 内存泄漏测试
4. 组件更新性能测试
5. 生成性能基准报告
创建性能测试文件src/__tests__/performance/ProductList.performance.test.tsx
性能测试代码:
import { render, screen, waitFor } from '@testing-library/react';
import { ProductList } from '../../components/ProductList';
import { performance } from 'perf_hooks';
// 生成测试数据
const generateMockProducts = (count: number) => {
return Array.from({ length: count }, (_, i) => ({
id: `product-${i}`,
name: `Product ${i}`,
price: Math.random() * 100,
category: ['Electronics', 'Clothing', 'Books'][Math.floor(Math.random() * 3)],
rating: Math.random() * 5,
discount: Math.random() > 0.5 ? Math.floor(Math.random() * 30) : 0,
image: `https://example.com/image${i}.jpg`,
}));
};
describe('ProductList Performance Tests', () => {
// 测试1: 大数据集渲染性能
it('should render 1000 products within acceptable time', async () => {
const mockProducts = generateMockProducts(1000);
jest.mock('../../hooks/useProducts', () => ({
useProducts: () => ({
products: mockProducts,
loading: false,
error: null,
refetch: jest.fn(),
}),
}));
const startTime = performance.now();
render(<ProductList />);
const endTime = performance.now();
const renderTime = endTime - startTime;
// 断言渲染时间应小于500ms
expect(renderTime).toBeLessThan(500);
console.log(`✓ Rendered 1000 products in ${renderTime.toFixed(2)}ms`);
});
// 测试2: 过滤性能
it('should filter products efficiently', async () => {
const mockProducts = generateMockProducts(1000);
jest.mock('../../hooks/useProducts', () => ({
useProducts: () => ({
products: mockProducts,
loading: false,
error: null,
refetch: jest.fn(),
}),
}));
const { rerender } = render(<ProductList searchQuery="" />);
const startTime = performance.now();
rerender(<ProductList searchQuery="Product 5" />);
const endTime = performance.now();
const filterTime = endTime - startTime;
// 断言过滤时间应小于100ms
expect(filterTime).toBeLessThan(100);
console.log(`✓ Filtered 1000 products in ${filterTime.toFixed(2)}ms`);
});
// 测试3: 排序性能
it('should sort products efficiently', async () => {
const mockProducts = generateMockProducts(1000);
jest.mock('../../hooks/useProducts', () => ({
useProducts: () => ({
products: mockProducts,
loading: false,
error: null,
refetch: jest.fn(),
}),
}));
const { rerender } = render(<ProductList sortBy="name" />);
const startTime = performance.now();
rerender(<ProductList sortBy="price" />);
const endTime = performance.now();
const sortTime = endTime - startTime;
// 断言排序时间应小于150ms
expect(sortTime).toBeLessThan(150);
console.log(`✓ Sorted 1000 products in ${sortTime.toFixed(2)}ms`);
});
// 测试4: 内存使用
it('should not leak memory', async () => {
const mockProducts = generateMockProducts(100);
jest.mock('../../hooks/useProducts', () => ({
useProducts: () => ({
products: mockProducts,
loading: false,
error: null,
refetch: jest.fn(),
}),
}));
// 获取初始内存使用
if (global.gc) global.gc(); // 手动触发垃圾回收
const initialMemory = process.memoryUsage().heapUsed;
// 渲染和卸载组件10次
for (let i = 0; i < 10; i++) {
const { unmount } = render(<ProductList />);
unmount();
}
// 再次触发垃圾回收
if (global.gc) global.gc();
const finalMemory = process.memoryUsage().heapUsed;
const memoryIncrease = finalMemory - initialMemory;
const memoryIncreaseMB = memoryIncrease / 1024 / 1024;
// 断言内存增长应小于10MB
expect(memoryIncreaseMB).toBeLessThan(10);
console.log(`✓ Memory increase: ${memoryIncreaseMB.toFixed(2)}MB`);
});
// 测试5: 重新渲染性能
it('should minimize unnecessary re-renders', async () => {
const mockProducts = generateMockProducts(100);
let renderCount = 0;
jest.mock('../../components/ProductCard', () => ({
ProductCard: React.memo(() => {
renderCount++;
return <div>Product Card</div>;
}),
}));
jest.mock('../../hooks/useProducts', () => ({
useProducts: () => ({
products: mockProducts,
loading: false,
error: null,
refetch: jest.fn(),
}),
}));
const { rerender } = render(<ProductList />);
// 记录初始渲染次数
const initialRenderCount = renderCount;
// 触发重新渲染(但props未改变)
rerender(<ProductList />);
// 断言ProductCard组件不应重新渲染
expect(renderCount).toBe(initialRenderCount);
console.log(`✓ No unnecessary re-renders detected`);
});
});
运行性能测试:
npm test -- src/__tests__/performance -- --no-coverage
测试输出示例:
PASS src/__tests__/performance/ProductList.performance.test.tsx
ProductList Performance Tests
✓ should render 1000 products within acceptable time (423ms)
✓ should filter products efficiently (87ms)
✓ should sort products efficiently (134ms)
✓ should not leak memory (5.23MB)
✓ should minimize unnecessary re-renders (0ms)
Test Suites: 1 passed, 1 total
Tests: 5 passed, 5 total
第五阶段:优化效果验证
运行Lighthouse测试
# 安装Lighthouse CI
npm install -g @lhci/cli
# 运行Lighthouse测试
lhci autorun --collect.url=http://localhost:3000
优化前后对比:
| 指标 | 优化前 | 优化后 | 改善 |
|---|---|---|---|
| 性能评分 | 32 | 94 | +194% |
| 首次内容绘制(FCP) | 4.2s | 1.1s | -74% |
| 最大内容绘制(LCP) | 8.7s | 2.0s | -77% |
| 首次输入延迟(FID) | 185ms | 42ms | -77% |
| 总阻塞时间(TBT) | 1,850ms | 180ms | -90% |
| 累积布局偏移(CLS) | 0.25 | 0.02 | -92% |
| 速度指数 | 6.8 | 2.1 | -69% |
Chrome DevTools对比
Performance面板:
优化前:
├─ Scripting: 4,230ms (红色)
├─ Rendering: 2,150ms (红色)
├─ Painting: 1,890ms (红色)
└─ System: 850ms
Total: 9,120ms
优化后:
├─ Scripting: 320ms (绿色)
├─ Rendering: 180ms (绿色)
├─ Painting: 120ms (绿色)
└─ System: 95ms
Total: 715ms
改善: 92%
Memory面板:
优化前:
├─ Initial: 45MB
├─ 浏览20页: 350MB
├─ DOM Nodes: 12,000
└─ Event Listeners: 850
优化后:
├─ Initial: 35MB
├─ 浏览20页: 48MB
├─ DOM Nodes: 1,800
└─ Event Listeners: 120
改善: 86%
真实用户监控(RUM)数据
部署1个月后收集的数据:
用户性能体验:
├─ 95th percentile LCP: 2.3s (目标 < 2.5s) ✓
├─ 95th percentile FID: 78ms (目标 < 100ms) ✓
├─ 95th percentile CLS: 0.08 (目标 < 0.1) ✓
├─ 跳出率: 35% → 22% (-37%)
├─ 平均停留时间: 2:45 → 4:12 (+53%)
└─ 转化率: 2.1% → 3.8% (+81%)
业务影响:
├─ 页面加载时间减少: 77%
├─ 服务器成本降低: 45% (更少的重试请求)
├─ 用户满意度提升: 65%
└─ 收入增加: 25% (转化率提升)
第六阶段:总结和最佳实践
完成的优化清单
## 优化项目清单
### ✅ Phase 1: 核心优化
- [x] ProductList组件 - 使用useMemo缓存计算
- [x] ProductCard - 实现React.memo
- [x] 列表虚拟化 (react-window)
- [x] 价格计算优化
### ✅ Phase 2: 数据优化
- [x] 实现localStorage缓存
- [x] 添加请求去重
- [x] 实现乐观更新
- [x] 错误重试机制
### ✅ Phase 3: 内存优化
- [x] 修复定时器泄漏
- [x] 修复事件监听器泄漏
- [x] 修复WebSocket泄漏
- [x] 添加AbortController清理
### ✅ Phase 4: 监控和测试
- [x] 集成Web Vitals
- [x] 创建性能监控面板
- [x] 编写性能测试
- [x] 建立性能基准
### ✅ Phase 5: 其他优化
- [x] 图片懒加载
- [x] 代码分割(React.lazy)
- [x] CSS优化(PurgeCSS)
- [x] Gzip压缩
性能优化最佳实践
1. 渲染优化
// ✅ 使用React.memo避免不必要的重新渲染
export const MyComponent = React.memo<Props>((props) => {
// 组件逻辑
}, (prevProps, nextProps) => {
// 自定义比较逻辑
return prevProps.id === nextProps.id;
});
// ✅ 使用useMemo缓存计算结果
const expensiveValue = useMemo(() => {
return computeExpensiveValue(a, b);
}, [a, b]);
// ✅ 使用useCallback缓存函数
const handleClick = useCallback(() => {
doSomething(a);
}, [a]);
2. 列表优化
// ✅ 使用虚拟化处理长列表
import { FixedSizeList } from 'react-window';
<FixedSizeList
height={600}
itemCount={1000}
itemSize={100}
width="100%"
>
{Row}
</FixedSizeList>
// ✅ 使用稳定的key
{items.map(item => (
<div key={item.id}> {/* ✓ 使用唯一ID */}
{item.name}
</div>
))}
3. 内存管理
// ✅ 总是清理副作用
useEffect(() => {
const timer = setTimeout(() => {}, 1000);
const subscription = subscribe();
return () => {
clearTimeout(timer);
subscription.unsubscribe();
};
}, []);
// ✅ 取消pending请求
useEffect(() => {
const abortController = new AbortController();
fetchData({ signal: abortController.signal });
return () => {
abortController.abort();
};
}, []);
4. 代码分割
// ✅ 使用React.lazy延 迟加载
const ProductDetail = React.lazy(() => import('./pages/ProductDetail'));
<Suspense fallback={<Spinner />}>
<ProductDetail />
</Suspense>
5. 性能监控
// ✅ 监控Core Web Vitals
import { getCLS, getFID, getLCP } from 'web-vitals';
getCLS(console.log);
getFID(console.log);
getLCP(console.log);
// ✅ 使用React DevTools Profiler
<Profiler id="MyComponent" onRender={onRenderCallback}>
<MyComponent />
</Profiler>
常见性能陷阱
## 避免这些常见错误
### ❌ 陷阱1: 在render中创建对象/数组
{items.map(item => (
<ProductCard
key={item.id}
style={{ margin: 10 }} // ❌ 每次render创建新对象
options={['a', 'b']} // ❌ 每次render创建新数组
/>
))}
### ✅ 正确做法: 移到const或useMemo
const cardStyle = { margin: 10 };
const cardOptions = ['a', 'b'];
{items.map(item => (
<ProductCard
key={item.id}
style={cardStyle}
options={cardOptions}
/>
))}
### ❌ 陷阱2: 不恰当的useEffect依赖
useEffect(() => {
fetchProducts(category);
}, []); // ❌ 缺少category依赖
### ✅ 正确做法: 包含所有依赖
useEffect(() => {
fetchProducts(category);
}, [category]);
### ❌ 陷阱3: 过早优化
// 为100个商品实现虚拟化 (过度优化)
if (products.length > 100) {
return <VirtualizedList />;
}
### ✅ 正确做法: 根据实际情况优化
// 只在确实需要时才优化
if (products.length > 1000) {
return <VirtualizedList />;
}
性能优化工作流
## 性能优化标准流程
### 1. 测量
- 使用Lighthouse建立基线
- 使用Chrome DevTools Profile识别瓶颈
- 使用React DevTools Profiler找出慢组件
- 收集真实用户监控数据
### 2. 分析
- 识别最严重的性能问题(二八定律)
- 确定优化优先级
- 估算优化投入和收益
### 3. 优化
- 从影响最大的问题开始
- 一次优化一个问题
- 保持代码可读性和可维护性
### 4. 验证
- 重新运行性能测试
- 对比优化前后的数据
- 确保没有引入新问题
### 5. 监控
- 在生产环境持续监控
- 设置性能预算
- 定期审查性能指标
### 6. 迭代
- 根据监控数据调整优化策略
- 持续改进性能
- 保持与业务需求的平衡
Claude Code在性能优化中的价值
## Claude Code如何加速性能优化
### 传统性能优化流程
├─ 手动分析代码: 2-4小时
├─ 识别性能问题: 1-2小时
├─ 编写优化代码: 3-5小时
├─ 测试和调试: 2-3小时
└─ 总计: 8-14小时
### 使用Claude Code
├─ 自动分析代码: 5-10分钟
├─ 智能识别问题: 2-5分钟
├─ 生成优化代码: 10-20分钟
├─ 自动化测试: 5-10分钟
└─ 总计: 30-60分钟
### 效率提升: 10-15倍
### Claude Code的优势
1. **快速识别**: 智能分析代码,自动识别性能反模式
2. **并行分析**: 同时检查多个文件,全面评估性能
3. **智能建议**: 基于最佳实践提供优化建议
4. **代码生成**: 自动生成优化后的代码
5. **测试生成**: 创建性能测试验证优化效果
6. **文档生成**: 自动生成绩效报告和文档
常见问题解答
Q1: 如何判断何时需要优化?
A: 遵循"过早优化是万恶之源"原则:
## 优化时机判断
### 不需要优化的情况:
- 组件渲染时间 < 16ms (60fps)
- 列表项 < 100个
- 用户没有反馈性能问题
- Lighthouse分数 > 90
### 需要优化的情况:
- 用户明确反馈卡顿
- Lighthouse分数 < 50
- 组件渲染时间 > 100ms
- 列表项 > 500个
- 内存持续增长
- CPU使用率长期 > 80%
Q2: 虚拟化一定会提升性能吗?
A: 不一定:
## 虚拟化适用场景
### ✅ 适合虚拟化:
- 列表项 > 500个
- 列表项高度固定或可预测
- 需要频繁滚动
- 单个组件渲染较慢
### ❌ 不适合虚拟化:
- 列表项 < 100个 (反而增加复杂度)
- 列表项高度差异巨大
- 很少滚动
- 单个组件渲染很快 (<1ms)
Q3: React.memo会不会滥用?
A: 会:
## React.memo使用指南
### ✅ 应该使用:
- 组件渲染开销大 (>10ms)
- 经常使用相同的props重新渲染
- 纯展示组件,不依赖外部状态
### ❌ 不应该使用:
- 轻量级组件 (<1ms)
- props频繁改变
- 有内部状态且经常更新
- 每次渲染都不同
### 最佳实践:
先测量,再优化。不要盲目memo所有组件。
Q4: 如何平衡性能和代码可读性?
A:
## 性能 vs 可读性
### 原则:
1. **可读性优先**: 在性能足够好的情况下,优先考虑可读性
2. **渐进优化**: 先写清晰代码,发现瓶颈再优化
3. **注释说明**: 复杂优化必须添加 详细注释
4. **提取函数**: 将优化逻辑封装到独立函数
### 示例:
// ❌ 过度优化,难以理解
const d= useMemo(()=>c.reduce((a,b)=>a+(b.p*(1-b.d/100)),0),[c])
// ✅ 优化但可读
const totalPrice = useMemo(() => {
return products.reduce((sum, product) => {
const discount = product.price * (product.discount / 100);
return sum + (product.price - discount);
}, 0);
}, [products]);
Q5: 如何追踪优化效果?
A: 建立完整的性能监控系统:
// 性能追踪示例
import { trackPerformance } from './analytics';
export const usePerformanceTracking = (operationName: string) => {
return useCallback(async <T>(
operation: () => Promise<T>
): Promise<T> => {
const startTime = performance.now();
try {
const result = await operation();
const endTime = performance.now();
const duration = endTime - startTime;
// 发送到分析服务
trackPerformance({
name: operationName,
duration,
success: true,
});
return result;
} catch (error) {
const endTime = performance.now();
const duration = endTime - startTime;
trackPerformance({
name: operationName,
duration,
success: false,
error: error instanceof Error ? error.message : 'Unknown',
});
throw error;
}
}, [operationName]);
};
// 使用
const trackRender = usePerformanceTracking('ProductList-render');
await trackRender(() => renderProducts());
总结
关键成果
性能提升3-5倍
- Lighthouse: 32 → 94 (+194%)
- 首屏加载: 8.7s → 2.0s (-77%)
- 交互响应: 185ms → 42ms (-77%)
用户体验改善
- 跳出率 -37%
- 停留时间 +53%
- 转化率 +81%
技术债务减少
- 修复10+内存泄漏
- 代码可维护性提升
- 建立性能监控体系
学到什么
-
系统化分析方法
- Lighthouse建立基线
- DevTools定位瓶颈
- Profiler分析组件
-
针对性优化策略
- 渲染优化(memo、useMemo、useCallback)
- 列表优化(虚拟化)
- 内存管理(清理副作用)
- 数据优化(缓存、去重)
-
性能监控和测试
- 集成Web Vitals
- 编写性能测试
- 建立监控体系
-
Claude Code加速
- 自动分析问题
- 生成优化代码
- 创建测试用例
- 效率提升10-15倍
下一步优化
进阶方向
- 服务端渲染(Next.js SSR)
- 边缘缓存(Cloudflare Workers)
- Web Workers(计算密集任务)
- PWA(离线功能)
- 性能预算自动化(CI/CD集成)
性能优化是持续过程,不是一次性任务。Claude Code帮你更高效识别和解决问题。
完整项目结构
ecommerce-app-optimized/
├── src/
│ ├── components/
│ │ ├── ProductList.tsx # ✓ useMemo优化
│ │ ├── ProductCard.tsx # ✓ React.memo
│ │ ├── VirtualProductList.tsx # ✓ 新增虚拟化
│ │ ├── SearchBar.tsx # ✓ 防抖
│ │ ├── FilterSidebar.tsx # ✓ 修复内存泄漏
│ │ └── PerformanceDashboard.tsx # ✓ 新增监控
│ ├── hooks/
│ │ ├── useProducts.ts # ✓ 缓存和重试
│ │ ├── usePerformanceMonitor.ts # ✓ 新增
│ │ └── useVirtualList.ts # ✓ 新增
│ ├── __tests__/
│ │ └── performance/
│ └── utils/
│ └── performance.ts # ✓ 新增
├── package.json # ✓ web-vitals
└── PERFORMANCE.md # ✓ 优化文档
参考资源
官方文档
推荐工具
相关文章
下一步
- 给项目跑Lighthouse
- 用Claude Code分析瓶颈
- 实施Phase 1优化
- 建立监控体系
- 持续迭代