React 性能剖析:用 Profiler 与火焰图定位重渲染
test12026-10-226 次阅读
为什么需要 Profiler
组件树大了以后,页面卡顿往往不是某段逻辑慢,而是一次状态更新触发了不该重渲染的子树。肉眼看不出来,必须靠测量。React DevTools 的 Profiler 面板记录了每一次 commit 的开销与组件,是定位重渲染的第一抓手。
用 Profiler 组件包裹关键路径
除了 DevTools 录制,也可以在代码里用 Profiler 组件,拿到某段子树渲染的耗时与触发原因,打印到控制台辅助排查。
import { Profiler } from "react";
function onRender(
id: string,
phase: "mount" | "update",
actualDuration: number,
) {
if (actualDuration > 5) {
console.warn(`[slow] ${id} ${phase} 用了 ${actualDuration.toFixed(2)}ms`);
}
}
export function Dashboard({ data }: { data: number[] }) {
return (
<Profiler id="Dashboard" onRender={onRender}>
<Chart data={data} />
<Sidebar />
</Profiler>
);
}看懂火焰图与高亮提交
火焰图里每一根横条是一个组件,宽度代表渲染耗时,颜色代表本次 commit 是否参与。点开某个组件,右侧会显示 Why did this render,告诉你是因为自身 state 变化、还是父组件 re-render 被顺带带下来的。找到被父级牵连的叶子节点,才是优化点。
先测量,再记忆化
不要一上来就套 useMemo。先用 Profiler 确认某段计算或某次重渲染确实昂贵,再用记忆化收口。下面这个例子里,filtered 列表只有在 items 或 keyword 变化时才重算,避免每次父组件渲染都白算一遍。
import { useMemo, useState } from "react";
export function SearchList({ items }: { items: string[] }) {
const [keyword, setKeyword] = useState("");
const filtered = useMemo(
() => items.filter((i) => i.includes(keyword)),
[items, keyword],
);
return (
<ul>
{filtered.map((i) => (
<li key={i}>{i}</li>
))}
</ul>
);
}关键结论
- 性能问题先看火焰图,别凭直觉加 memo。
- 重渲染的元凶通常是父组件 re-render 顺带拖累,而不是子组件自己慢。
- 记忆化有成本,只在测量结果支持时使用。
T
test1
文章作者
为什么需要 Profiler 组件树大了以后,页面卡顿往往不是某段逻辑慢,而是一次状态更新触发了不该重渲染的子树。肉眼看...
- 分类
- 技术
- 发布时间
- 2026-10-22
- 字数
- 约 1412 字
- 阅读
- 6 次
