在大型 React 项目中,经常会遇到一个典型问题:页面频繁 re-render 导致卡顿,影响用户体验。这篇文章将从真实开发场景出发,讲解我们是如何通过 React.memo
、useCallback
、懒加载、代码分割、Virtual DOM diff 工具等方式,有效减轻渲染负担,让前端“飞”起来的!
你点了一个按钮,却发现页面整个重新渲染了;你滑动表格时掉帧卡顿;你打开一个新页面时还加载了不相关的模块……这些问题说白了,大多数都跟 React 的渲染机制有关。
而我们今天要解决的问题就是:
React 采用 Virtual DOM,每次组件状态变更,都会触发 从根组件递归进行 diff 对比并更新,所以如果你更新了某个状态,但没做优化,就可能导致整棵组件树重算。
比如下面的例子:
function App() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>点击</button>
<Header />
<Content />
</>
);
}
你每次点击按钮时,不管 Header
和 Content
有没有用到 count
,它们还是会重新渲染一次。
适用场景:组件 props 不变时不需要更新的子组件
const Header = React.memo(function Header({ title }) {
console.log("Header 渲染了");
return <h1>{title}</h1>;
});
<Header title="欢迎回来" />
如果 title
没变,哪怕父组件更新了,Header
都不会重新渲染。
const handleClick = useCallback(() => {
console.log("clicked");
}, []);
为什么要这么做?因为如果你这样传函数:
<Child onClick={() => doSomething()} />
每次渲染都会生成一个新的函数引用,导致 Child
每次都以为自己变了,重新渲染。
适用场景:部分页面或大型组件不必首屏加载
const HeavyComponent = React.lazy(() => import('./HeavyComponent'));
<Suspense fallback={<div>加载中...</div>}>
<HeavyComponent />
</Suspense>
这个方式会把 HeavyComponent
单独打包成 chunk,只有用到时才加载。
适用场景:渲染 1000 条数据,页面卡顿
推荐用:react-window
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>
只渲染可见区域的元素,超高性能。
开发环境可以使用:
npm install @welldone-software/why-did-you-render
import React from 'react';
import whyDidYouRender from '@welldone-software/why-did-you-render';
if (process.env.NODE_ENV === 'development') {
whyDidYouRender(React);
}
原始问题:
function Form() {
const [count, setCount] = useState(0);
return (
<>
<button onClick={() => setCount(count + 1)}>Add</button>
<FormFields />
</>
);
}
解决:
const FormFields = React.memo(() => {
return (
<>
<input />
<select />
</>
);
});
使用 lazy loading:
const Chart = React.lazy(() => import('./Chart'));
首屏只加载骨架屏,用户交互时再加载图表模块,减少初始资源下载量。
当组件 props 固定或更新频率极低时使用;复杂组件建议搭配 useMemo
对 props 做深比较或定制比较函数。
有可能是组件 render 太频繁,排查办法:
不是,有时候 props 是引用类型(如数组/对象),每次 render 引用变了还是会触发更新,建议配合 useMemo
和 useCallback
使用。
React 项目的性能优化,说白了就是:避免重复渲染,拆分渲染任务,按需加载资源,合理利用浏览器能力。
你可以从这几个方面着手:
最重要的是,每一个优化动作都不是一劳永逸,而应该配合业务特点和实际场景灵活使用。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。