Appearance
性能优化策略总结 - 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性能优化策略的核心要点:
- 渲染优化: memo/useMemo/useCallback
- 列表优化: 虚拟滚动/key/懒加载
- Bundle优化: 代码分割/Tree Shaking
- 网络优化: CDN/压缩/缓存
- 监控: DevTools/Web Vitals
- 状态管理: 合理拆分/Context优化
掌握这些策略可以显著提升React应用性能。