打开任何一个 AI 辅助开发的 React 项目。你大概率会看到一样的画面:useMemouseCallbackReact.memo 铺天盖地,仿佛不写就会崩。
但 2026 年了React Compiler 已经正式落地。你手动写的那些“调整”,很多不但没用,还在拖慢你的代码。
先说为什么要改
React Compiler做了一件事:在编译阶段自动分析组件,在表达式级别做细粒度 memoization。
这代表着的观点是。你手写的 useMemo/useCallback/React.memo——编译器都能自动做,而且做得更细、更准确。按理说,
手动写的问题在于:
| 维度 | 手动调整 | React Compiler |
| 粒度 | 组件/Hook 级别 | 表达式级别 |
| 准确性 | 依赖数组经常写错。可能遗漏缓存更新 | 编译器分析,不会遗漏缓存失效问题 |
| 代码量 | 多30‑%包装代码零额外代码?不对,是多了包装逻辑和闭包开销。其实, | 无额外包装,直接使用原始表达式。 |
| 维护成本 | 依赖变了要手动更新;易忘记更新导致 bug, | 自动追踪依赖,无需人工干预。 |
| 出错概率
| 依赖数组写错导致缓存永远不更新。按理说, | "无"——因为编译器自行分析。 |
ESLint React v5.3 已经加了 No‑Unnecessary‑Use‑Memo / No‑Unnecessary‑Use‑Callback — 官方工具链都在告诉你别写了。
下面逐个看 5 个已经变成反模式的“调整”。
反模式 1:用 useMemo 包裹所有计算
最常见的 AI 生成代码模式:
function UserList {
const filteredUsers = useMemo => {
return users.filter);},),const sortedUsers = useMemo => {
return .sort=>a.name.localeCompare);},),const stats = useMemo => ({
total这方面。sortedUsers.length,active: sortedUsers.filter.length,}),);return
{/* ... */}
}
A: TWO> THREE?看似分离,却多出了三段闭包,维护成本翻倍;可读性下降一半,每段都有自己的依赖数组,需要同步更新。
2026 年的新写法:
function UserList {
const sorted = users
.filter)
.sort=>a.name.localeCompare);const stats = {
从total来看,sorted.length。active: sorted.filter.length,};return
{/* ... */}
}
B: A single pass guarantees compiler will memoize expression-level dependencies automatically.
从唯一例外来看,
-
If you really have a heavy calculation and you prove it is a bottleneck with Profiler → keep
{useMemo}. In all or scenarios it's noise.
-
The compiler's automatic memoization already covers it.
-
This rule applies only when profiling shows genuine slowdown.
-
Avoid unnecessary manual memoization unless performance proves orwise.
反模式 2:用 useCallback 包裹所有传给子组件的函数
function Dashboard {
const = useState;const handleClick = useCallback=>{setCount;
},),const handleReset = useCallback=>{setCount;},),const handleExport = useCallback=>{exportData;},),return (
<>
<>
);}
}
-
No real benefit unless children are wrapped in
.
-
If no memoization at child level,this stable reference is wasted overhead.
-
The dependency array of
{handleExport}。containing count,defeats purpose .
-
This pattern originates from outdated “best practice” training data—now it's just noise.
function Dashboard {
const = useState;return (
<>
。