react-compiler

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

React Compiler

React Compiler

Rule

规则

The compiler memoizes. You do not.
In any React 19+ codebase with the compiler enabled, do not add
useMemo
,
useCallback
, or
React.memo
by default. The compiler handles memoization at finer granularity than a human writes, and adding manual versions is at best noise. This is the most common failure mode in LLM-generated React: the bulk of any agent's React training corpus is pre-compiler, so the default output skews toward manual memoization.
编译器负责记忆化,你无需手动操作。
在任何启用了编译器的React 19+代码库中,默认不要添加
useMemo
、
useCallback
或
React.memo
。编译器能以比人工更精细的粒度处理记忆化,手动添加这些代码充其量只是冗余内容。这是大语言模型(LLM)生成React代码时最常见的问题:大多数AI训练语料都是编译器出现之前的React内容,因此默认输出会偏向手动记忆化。

Default behavior when writing React

编写React代码时的默认做法

Write components plainly:
tsx
function DashboardRow({ entity, onSelect }) {
  const label = formatLabel(entity);
  const total = entity.items.reduce((sum, i) => sum + i.value, 0);
  return (
    <Row onClick={() => onSelect(entity.id)}>
      <Label>{label}</Label>
      <Total>{total}</Total>
    </Row>
  );
}
Not:
tsx
const DashboardRow = memo(({ entity, onSelect }) => {
  const formatted = useMemo(() => ({ /* ... */ }), [entity]);
  const handleClick = useCallback(() => onSelect(entity.id), [entity.id, onSelect]);
  return /* ... */;
});
The compiler produces the equivalent of the first from any input that follows the Rules of React. Adding the second by hand is noise and can interfere with the compiler's analysis.
简洁地编写组件:
tsx
function DashboardRow({ entity, onSelect }) {
  const label = formatLabel(entity);
  const total = entity.items.reduce((sum, i) => sum + i.value, 0);
  return (
    <Row onClick={() => onSelect(entity.id)}>
      <Label>{label}</Label>
      <Total>{total}</Total>
    </Row>
  );
}
而非:
tsx
const DashboardRow = memo(({ entity, onSelect }) => {
  const formatted = useMemo(() => ({ /* ... */ }), [entity]);
  const handleClick = useCallback(() => onSelect(entity.id), [entity.id, onSelect]);
  return /* ... */;
});
只要遵循React规则,编译器就能生成与第一种写法等效的代码。手动编写第二种写法不仅冗余,还会干扰编译器的分析。

Three exceptions where manual memoization is still required

仍需手动记忆化的三种例外情况

Keep manual
useMemo
or
useCallback
only in these cases:
  1. Referential identity for non-React consumers. Values feeding into
    addEventListener
    , an
    IntersectionObserver
    , third-party libraries with their own
    ===
    checks, anything outside React that retains the reference.
  2. Expensive non-render work the compiler cannot see through. Parsing a large blob, building a large index, calling a heavy library. Keep, and add a comment explaining why.
  3. Effect dependencies that must be stable for correctness. If a dependency would trip the effect every render without the wrap, keep it.
Anything outside these three cases gets deleted.
仅在以下三种情况下保留手动
useMemo
或
useCallback
:
  1. 为非React消费者保持引用一致性:值传入
    addEventListener
    、
    IntersectionObserver
    、有自身
    ===
    检查的第三方库,或任何React外部会保留引用的场景。
  2. 编译器无法识别的高开销非渲染工作:解析大文件、构建大型索引、调用重型库。保留时需添加注释说明原因。
  3. 为确保正确性必须保持稳定的Effect依赖项:如果不包裹该依赖项,Effect会在每次渲染时触发,此时需要保留。
不属于这三种情况的手动记忆化代码都应删除。

Audit workflow on an existing codebase

现有代码库的审计流程

  1. Confirm compiler is enabled. Check
    next.config
    (
    experimental.reactCompiler
    ),
    vite.config
    or
    babel.config
    (
    babel-plugin-react-compiler
    ), or framework defaults for Expo and TanStack Start. If not enabled, propose enabling first. Do not strip memoization on a compiler-off codebase.
  2. Confirm
    eslint-plugin-react-hooks
    is at v6+.
    The compiler rules merged in from the deprecated
    eslint-plugin-react-compiler
    in late 2025.
  3. Promote lint rules to
    error
    .
    recommended
    ships most at
    warn
    , which means CI does not fail on silent compiler skips. See lint-setup.md for the strict configuration.
  4. Sweep manual memoization. Delete
    useMemo
    ,
    useCallback
    ,
    React.memo
    that do not match one of the three exceptions.
  5. Run lint. Fix silent skips iteratively. Silent skips cascade: fixing an upstream skip can reveal a second issue downstream. First run gives the count. Subsequent runs give the truth.
  6. Track
    "use no memo"
    directives.
    Each is a performance cliff with a TODO behind it. Grep the count over time as a health metric.
  1. 确认编译器已启用:检查
    next.config
    (
    experimental.reactCompiler
    )、
    vite.config
    或
    babel.config
    (
    babel-plugin-react-compiler
    ),或Expo和TanStack Start等框架的默认配置。如果未启用,建议先启用。不要在未启用编译器的代码库中移除记忆化代码。
  2. 确认
    eslint-plugin-react-hooks
    版本为v6+
    :编译器相关规则在2025年底从已废弃的
    eslint-plugin-react-compiler
    合并到了该插件中。
  3. 将lint规则升级为
    error
    级别
    :
    recommended
    配置中大多数规则为
    warn
    级别,这意味着CI不会因编译器静默跳过而失败。请参考lint-setup.md获取严格配置。
  4. 清理手动记忆化代码:删除不符合上述三种例外情况的
    useMemo
    、
    useCallback
    、
    React.memo
    。
  5. 运行lint,迭代修复静默跳过问题:静默跳过会连锁反应:修复上游的跳过问题可能会暴露下游的第二个问题。第一次运行会得到问题数量,后续运行会得到真实情况。
  6. 跟踪
    "use no memo"
    指令
    :每个这类指令背后都存在性能瓶颈和TODO事项。定期统计其数量作为代码健康度指标。

When the compiler silently bails

编译器静默退出的情况

Five patterns drop the surrounding function out of compilation. The lint rules above catch them when configured strictly. Full list, code examples, and fixes in exceptions.md.
有五种模式会导致相关函数退出编译。上述lint规则在严格配置下会捕获这些情况。完整列表、代码示例及修复方法请参考exceptions.md。

Output format for an audit

审计输出格式

file: <path>
findings:
  - removed: <useMemo | useCallback | memo> @ <line>, compiler handles
  - kept: <useMemo | useCallback> @ <line>, reason: <ref-identity | expensive | effect-dep>
silent bails detected:
  - <pattern> @ <line>: <one-line fix>
file: <路径>
findings:
  - removed: <useMemo | useCallback | memo> @ <行号>, compiler handles
  - kept: <useMemo | useCallback> @ <行号>, reason: <ref-identity | expensive | effect-dep>
silent bails detected:
  - <模式> @ <行号>: <单行修复方案>

Source

来源

Based on The React Compiler at Eighteen Months. Sibling detail in exceptions.md and lint-setup.md.
基于The React Compiler at Eighteen Months。详细补充内容请见exceptions.md和lint-setup.md。