React 性能优化全面指南
React 应用性能优化是一个系统工程,需要从多个层面进行优化。以下是一套完整的 React 性能优化策略,涵盖从基础到高级的各种技术:
一、组件级优化策略
1. 记忆化组件
- React.memo:避免不必要的重新渲染
const MemoizedComponent = React.memo(MyComponent, (prevProps, nextProps) => { return prevProps.id === nextProps.id; });
2. 状态精细化
- 避免在根组件存储所有状态
- 将状态下放到使用它的最小组件
// 不好的做法:状态提升过高 const App = () => { const [user, setUser] = useState({}); return <Profile user={user} />; }; // 好的做法:状态下沉 const Profile = () => { const [user, setUser] = useState({}); return <UserCard user={user} />; };
3. 引用类型优化
useCallback:缓存函数引用
const handleClick = useCallback(() => { console.log('Clicked'); }, []);
useMemo:缓存计算结果
const expensiveValue = useMemo(() => { return computeExpensiveValue(a, b); }, [a, b]);
4. 避免内联对象
- 内联对象会导致每次渲染都创建新引用
// 不好的做法 <MyComponent style={{ color: 'red' }} /> // 好的做法 const style = useMemo(() => ({ color: 'red' }), []); <MyComponent style={style} />
二、渲染优化策略
1. 虚拟化长列表
- 使用 react-window 或 react-virtualized
import { FixedSizeList as List } from 'react-window'; const Row = ({ index, style }) => ( <div style={style}>Row {index}</div> ); const VirtualList = () => ( <List height={600} itemCount={1000} itemSize={35} width={300}> {Row} </List> );
2. 延迟加载组件
- React.lazy + Suspense
const HeavyComponent = React.lazy(() => import('./HeavyComponent')); const App = () => ( <Suspense fallback={<div>Loading...</div>}> <HeavyComponent /> </Suspense> );
3. 分片渲染
- 使用 setTimeout 或 requestIdleCallback 拆分渲染任务
const renderChunk = (startIndex, endIndex) => { requestIdleCallback(() => { // 渲染部分内容 for (let i = startIndex; i < endIndex; i++) { renderItem(data[i]); } }); };
三、状态管理优化
1. 状态选择器优化
- 在 Redux 中使用 reselect
import { createSelector } from 'reselect'; const selectItems = state => state.items; const selectFilter = state => state.filter; const selectFilteredItems = createSelector( [selectItems, selectFilter], (items, filter) => items.filter(item => item.includes(filter)) );
2. Context 优化
- 拆分 Context 避免不必要更新
// 创建多个 Context const UserContext = createContext(); const ThemeContext = createContext(); // 使用 Context Selector import { useContextSelector } from 'use-context-selector'; const UserName = () => { const name = useContextSelector(UserContext, v => v.name); return <div>{name}</div>; };
3. 状态更新批处理
- React 18 自动批处理异步操作
- 手动批处理(React 17 及以下)
// React 17 需要手动批处理 import { unstable_batchedUpdates } from 'react-dom'; const clickHandler = () => { setTimeout(() => { // 模拟异步 ReactDOM.unstable_batchedUpdates(() => { // 仅仅加了unstable_batchedUpdates // 这里的两个setState会合并执行一次。 setNum(2); setStr('c'); }); }, 1000); }
四、网络与加载优化
1. 资源预加载
- 使用 preload 和 prefetch
<link rel="preload" href="critical.css" as="style"> <link rel="prefetch" href="optional.js" as="script">
2. 代码分割
- 基于路由的代码分割
const Home = lazy(() => import('./Home')); const About = lazy(() => import('./About')); const App = () => ( <Routes> <Route path="/" element={<Suspense fallback="..."><Home /></Suspense>} /> <Route path="/about" element={<Suspense fallback="..."><About /></Suspense>} /> </Routes> );
3. 图片优化
- 使用 next/image(Next.js)或 react-lazy-load-image
import { LazyLoadImage } from 'react-lazy-load-image-component'; <LazyLoadImage src="image.jpg" placeholderSrc="placeholder.jpg" effect="blur" />
六、性能监测与分析工具
1. React DevTools
- 组件渲染时间分析
- Highlight updates when components render
2. Chrome Performance 工具
- 录制性能时间线
- 分析 JavaScript 执行时间
3. React Profiler API
- 编程式性能分析
<Profiler id="MyApp" onRender={onRenderCallback}> <App /> </Profiler> function onRenderCallback( id, // 组件ID phase, // "mount" 或 "update" actualDuration, // 本次渲染花费时间 baseDuration, // 不使用memoization的估计时间 startTime, // 开始时间 commitTime, // 提交时间 interactions // 本次更新相关的交互 ) { // 记录或分析这些信息 }
4. Lighthouse 审计
- 全面的性能评分
- 优化建议
七、常见性能陷阱及解决方案
问题 | 表现 | 解决方案 |
---|---|---|
过度渲染 | 组件频繁重渲染 | 使用 React.memo, useMemo |
长列表性能差 | 滚动卡顿 | 虚拟化列表 |
首屏加载慢 | LCP 时间过长 | 代码分割, 预加载 |
JavaScript 阻塞 | TTI 延迟 | 代码分割, 懒加载 |
状态管理不当 | 无关组件更新 | 精细化状态管理 |
通过综合应用这些优化策略,可以显著提升 React 应用的性能,提供更流畅的用户体验。记住,优化是一个持续的过程,需要根据应用的具体情况进行调整和迭代。