首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >React.memo + useCallback 到底怎么用?一文讲清楚

React.memo + useCallback 到底怎么用?一文讲清楚

原创
作者头像
连连LL
发布2025-07-03 14:11:02
发布2025-07-03 14:11:02
1480
举报
文章被收录于专栏:技术技术

摘要

在大型 React 项目中,经常会遇到一个典型问题:页面频繁 re-render 导致卡顿,影响用户体验。这篇文章将从真实开发场景出发,讲解我们是如何通过 React.memouseCallback、懒加载、代码分割、Virtual DOM diff 工具等方式,有效减轻渲染负担,让前端“飞”起来的!

引言:你是否遇到过这些 React 性能坑?

你点了一个按钮,却发现页面整个重新渲染了;你滑动表格时掉帧卡顿;你打开一个新页面时还加载了不相关的模块……这些问题说白了,大多数都跟 React 的渲染机制有关。

而我们今天要解决的问题就是:

  • 如何避免不必要的重新渲染
  • 如何实现组件级性能隔离
  • 如何延迟加载非关键代码
  • 如何借助工具找出瓶颈

理解 React 渲染性能问题的根源

React 组件的更新触发机制

React 采用 Virtual DOM,每次组件状态变更,都会触发 从根组件递归进行 diff 对比并更新,所以如果你更新了某个状态,但没做优化,就可能导致整棵组件树重算。

比如下面的例子:

代码语言:jsx
复制
function App() {
  const [count, setCount] = useState(0);

  return (
    <>
      <button onClick={() => setCount(count + 1)}>点击</button>
      <Header />
      <Content />
    </>
  );
}

你每次点击按钮时,不管 HeaderContent 有没有用到 count,它们还是会重新渲染一次。

优化手段详解 + 实战示例

使用 React.memo 避免重复渲染

适用场景:组件 props 不变时不需要更新的子组件

代码语言:jsx
复制
const Header = React.memo(function Header({ title }) {
  console.log("Header 渲染了");
  return <h1>{title}</h1>;
});
代码语言:jsx
复制
<Header title="欢迎回来" />

如果 title 没变,哪怕父组件更新了,Header 都不会重新渲染。

使用 useCallback 优化函数 props 的引用变化

代码语言:jsx
复制
const handleClick = useCallback(() => {
  console.log("clicked");
}, []);

为什么要这么做?因为如果你这样传函数:

代码语言:jsx
复制
<Child onClick={() => doSomething()} />

每次渲染都会生成一个新的函数引用,导致 Child 每次都以为自己变了,重新渲染。

使用懒加载与 Code Splitting 优化首次加载时间

适用场景:部分页面或大型组件不必首屏加载

代码语言:jsx
复制
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));

<Suspense fallback={<div>加载中...</div>}>
  <HeavyComponent />
</Suspense>

这个方式会把 HeavyComponent 单独打包成 chunk,只有用到时才加载。

切分列表渲染,避免一次渲染太多项

适用场景:渲染 1000 条数据,页面卡顿

推荐用:react-window

代码语言:jsx
复制
import { FixedSizeList as List } from 'react-window';

<List
  height={400}
  itemCount={1000}
  itemSize={35}
  width={300}
>
  {({ index, style }) => (
    <div style={style}>Row {index}</div>
  )}
</List>

只渲染可见区域的元素,超高性能。

借助工具排查渲染瓶颈

开发环境可以使用:

  • React DevTools:查看组件 render 次数和 props 变化
  • why-did-you-render:显示哪些组件“白渲染”了
  • Flipper 插件:可视化查看 props 和状态的变更流转
代码语言:bash
复制
npm install @welldone-software/why-did-you-render
代码语言:jsx
复制
import React from 'react';
import whyDidYouRender from '@welldone-software/why-did-you-render';

if (process.env.NODE_ENV === 'development') {
  whyDidYouRender(React);
}

实战场景案例分析

按钮点击导致整个表单组件刷新

原始问题:

代码语言:jsx
复制
function Form() {
  const [count, setCount] = useState(0);
  return (
    <>
      <button onClick={() => setCount(count + 1)}>Add</button>
      <FormFields />
    </>
  );
}

解决:

代码语言:jsx
复制
const FormFields = React.memo(() => {
  return (
    <>
      <input />
      <select />
    </>
  );
});

大型 Dashboard 首屏加载很慢

使用 lazy loading:

代码语言:jsx
复制
const Chart = React.lazy(() => import('./Chart'));

首屏只加载骨架屏,用户交互时再加载图表模块,减少初始资源下载量。

QA 环节:你可能关心的问题

Q1:memo 什么时候用?

当组件 props 固定或更新频率极低时使用;复杂组件建议搭配 useMemo 对 props 做深比较或定制比较函数。

Q2:页面卡顿但没有报错?

有可能是组件 render 太频繁,排查办法:

  • 查看是否不必要地更新了状态(state)
  • 是否用了匿名函数 props
  • 是否一次渲染太多数据

Q3:React.memo 没用,是不是白用了?

不是,有时候 props 是引用类型(如数组/对象),每次 render 引用变了还是会触发更新,建议配合 useMemouseCallback 使用。

总结

React 项目的性能优化,说白了就是:避免重复渲染,拆分渲染任务,按需加载资源,合理利用浏览器能力

你可以从这几个方面着手:

  • memo + useCallback 降低 render 次数
  • lazy + Suspense 优化首屏
  • 虚拟滚动优化大列表
  • 工具可视化分析瓶颈

最重要的是,每一个优化动作都不是一劳永逸,而应该配合业务特点和实际场景灵活使用。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 摘要
  • 引言:你是否遇到过这些 React 性能坑?
  • 理解 React 渲染性能问题的根源
    • React 组件的更新触发机制
  • 优化手段详解 + 实战示例
    • 使用 React.memo 避免重复渲染
    • 使用 useCallback 优化函数 props 的引用变化
    • 使用懒加载与 Code Splitting 优化首次加载时间
    • 切分列表渲染,避免一次渲染太多项
    • 借助工具排查渲染瓶颈
  • 实战场景案例分析
    • 按钮点击导致整个表单组件刷新
    • 大型 Dashboard 首屏加载很慢
  • QA 环节:你可能关心的问题
    • Q1:memo 什么时候用?
    • Q2:页面卡顿但没有报错?
    • Q3:React.memo 没用,是不是白用了?
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档