005-React性能优化

React 性能优化深度指南

除了使用 Performance 工具分析性能瓶颈外,React 应用还有多种高效的优化策略。下面从组件设计、渲染控制、资源管理等维度全面解析性能优化方案:

一、组件级优化策略

1. 渲染控制技术

技术 实现方式 适用场景
React.memo const MemoComp = React.memo(MyComp) 纯展示组件,Props 不变时不重渲染
useMemo const data = useMemo(() => transform(rawData), [rawData]) 复杂计算缓存,避免重复执行
useCallback const handler = useCallback(() => {...}, [deps]) 防止回调函数重复创建导致子组件重渲染
PureComponent class MyComp extends React.PureComponent Class 组件浅比较优化
shouldComponentUpdate shouldComponentUpdate(nextProps, nextState) Class 组件细粒度更新控制

useMemo 与 useCallback 最佳实践:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Parent() {
const [count, setCount] = useState(0);

// 避免每次渲染创建新函数
const increment = useCallback(() => setCount(c => c + 1), []);

// 避免每次渲染重新计算
const formattedCount = useMemo(() => `Count: ${count}`, [count]);

return (
<div>
<Child onClick={increment} text={formattedCount} />
<ExpensiveComponent data={heavyData} />
</div>
);
}

const Child = React.memo(({ onClick, text }) => (
<button onClick={onClick}>{text}</button>
));

2. 组件分割原则

  • 按功能拆分:将大型组件拆分为多个小型专用组件
  • 提取高频更新部分:隔离状态变化频繁的 UI 区域
  • 延迟加载边界:在组件树中设置 React.lazy 分割点
1
2
3
4
5
6
7
8
9
10
// 组件分割示例
function UserDashboard() {
return (
<div>
<UserProfile /> {/* 静态内容 */}
<UserStatistics /> {/* 数据驱动,频繁更新 */}
<RecentActivity /> {/* 独立更新区域 */}
</div>
);
}

二、状态管理优化

1. 状态提升与下沉策略

策略 描述 优化效果
状态提升 将状态移动到共同父组件 减少跨组件通信
状态下沉 将状态移动到使用位置 避免无关组件重渲染
状态隔离 使用 Context + useMemo 精准控制消费者更新

2. 高效状态更新模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ✅ 函数式更新避免依赖旧状态
setCount(prev => prev + 1);

// ✅ 批量状态更新
const updateValues = () => {
setValueA(1);
setValueB(2);
// React 18+ 自动批处理
};

// ❌ 避免在循环中连续setState
data.forEach(item => {
setList(prev => [...prev, item]); // 低效
});

// ✅ 使用临时变量批量更新
const newList = [];
data.forEach(item => newList.push(item));
setList(newList);

3. Context 优化方案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 创建分拆的 Context
const UserContext = React.createContext();
const SettingsContext = React.createContext();

// 优化消费组件
const UserProfile = () => {
// 只订阅需要的 Context
const user = useContext(UserContext);
return <div>{user.name}</div>;
};

// 使用记忆化 Provider 值
function App() {
const [user, setUser] = useState(null);

// ✅ 避免每次渲染创建新对象
const userValue = useMemo(() => ({ user, setUser }), [user]);

return (
<UserContext.Provider value={userValue}>
<MainLayout />
</UserContext.Provider>
);
}

三、渲染性能提升

1. 虚拟化长列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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. 时间分片策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 使用 requestIdleCallback 分割任务
const processChunk = (start) => {
const end = Math.min(start + 100, largeDataSet.length);

for (let i = start; i < end; i++) {
// 处理数据块
}

if (end < largeDataSet.length) {
requestIdleCallback(() => processChunk(end));
}
};

// 初始调用
requestIdleCallback(() => processChunk(0));

3. 动画优化技巧

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 使用 CSS transform 代替 top/left
.animated-item {
transition: transform 0.3s ease;
will-change: transform; /* 提示浏览器优化 */
}

// React 动画库推荐
import { useSpring, animated } from '@react-spring/web';

function FadeIn() {
const props = useSpring({
opacity: 1,
from: { opacity: 0 },
config: { tension: 300, friction: 20 }
});

return <animated.div style={props}>Fades in</animated.div>;
}

四、资源加载优化

1. 代码分割策略

技术 实现方式 效果
路由级分割 const Home = React.lazy(() => import('./Home')) 按路由加载
组件级分割 const Map = React.lazy(() => import('./Map')) 按需加载重组件
预加载 <link rel="preload" href="module.js" as="script"> 提前加载关键资源
1
2
3
4
5
6
7
8
9
10
11
12
// 带加载状态的代码分割
const ChatWidget = React.lazy(() => import('./ChatWidget'));

function App() {
return (
<div>
<Suspense fallback={<Spinner />}>
<ChatWidget />
</Suspense>
</div>
);
}

2. 资源优化技术

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 图片优化
<img
src="image.jpg"
srcSet="image-480w.jpg 480w, image-800w.jpg 800w"
sizes="(max-width: 600px) 480px, 800px"
alt="Responsive"
loading="lazy"
/>

// 字体优化
<style>
@font-face {
font-family: 'CustomFont';
src: url('font.woff2') format('woff2');
font-display: swap; /* 避免阻塞渲染 */
}
</style>

五、构建与运行时优化

1. 构建工具配置

1
2
3
4
5
6
7
8
9
10
11
12
13
// webpack.config.js
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 30000, // 30KB 以上拆包
},
runtimeChunk: 'single', // 分离运行时
},
plugins: [
new BundleAnalyzerPlugin(), // 分析包大小
]
};

2. 服务端渲染优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Next.js 优化示例
export async function getServerSideProps() {
const data = await fetchData();

return {
props: { data },
// 增量静态再生 (ISR)
revalidate: 60, // 每60秒重新生成
};
}

// 流式渲染
import { renderToPipeableStream } from 'react-dom/server';

const stream = renderToPipeableStream(<App />, {
bootstrapScripts: ['/main.js'],
onShellReady() {
res.setHeader('Content-type', 'text/html');
stream.pipe(res);
}
});

六、React 18+ 新特性优化

1. 并发模式特性

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 使用 useTransition 管理耗时操作
function SearchBox() {
const [query, setQuery] = useState('');
const [results, setResults] = useState([]);
const [isPending, startTransition] = useTransition();

const handleChange = (e) => {
const value = e.target.value;
setQuery(value);

// ✅ 标记非紧急更新
startTransition(() => {
fetchResults(value).then(setResults);
});
};

return (
<div>
<input value={query} onChange={handleChange} />
{isPending ? <Spinner /> : <Results list={results} />}
</div>
);
}

2. 服务端 Suspense 流式渲染

1
2
3
4
5
6
7
8
9
10
// 服务端组件 (Next.js 13+)
async function UserProfile({ userId }) {
const user = await fetchUser(userId);
return <Profile user={user} />;
}

// 客户端使用
<Suspense fallback={<ProfileSkeleton />}>
<UserProfile userId={123} />
</Suspense>

七、性能优化检查清单

  1. 渲染优化

    • 使用 React.memo/PureComponent 避免无效渲染
    • 正确使用 useMemo/useCallback 缓存
    • 确保依赖数组完整且准确
  2. 状态管理

    • 避免在渲染中直接修改状态
    • 使用批量更新减少渲染次数
    • 复杂状态使用 useReducer 替代 useState
  3. 资源加载

    • 实现路由级和组件级代码分割
    • 图片资源使用懒加载和响应式
    • 关键资源添加预加载
  4. 构建优化

    • 配置代码拆分配置
    • 移除未使用代码 (Tree Shaking)
    • 压缩生产环境资源
  5. 高级特性

    • 长列表使用虚拟化技术
    • 动画使用 CSS transform/will-change
    • 耗时操作使用 useTransition

总结:性能优化决策树

1
2
3
4
5
6
7
8
9
10
graph TD
A[性能问题] --> B{组件重渲染过多?}
B -->|是| C[使用 React.memo/useMemo/useCallback]
B -->|否| D{状态更新效率低?}
D -->|是| E[优化状态结构/批量更新]
D -->|否| F{资源加载慢?}
F -->|是| G[代码分割/预加载/懒加载]
F -->|否| H{大数据量操作?}
H -->|是| I[虚拟化/时间分片/Web Worker]
H -->|否| J[使用 Performance 工具深入分析]

通过组合使用这些策略,即使不使用 Performance 工具,也能显著提升 React 应用性能。最佳实践是预防优于修复 - 在开发过程中持续应用这些模式,而非在性能问题出现后才开始优化。