React Compiler 是一款全新的构建时工具,可自动优化你的 React 应用。它使用纯 JavaScript,并理解 React 的规则,因此你无需重写任何代码即可使用它。
¥React Compiler is a new build-time tool that automatically optimizes your React app. It works with plain JavaScript, and understands the Rules of React, so you don’t need to rewrite any code to use it.
你将学习到
-
React 编译器的功能
¥What React Compiler does
-
编译器入门
¥Getting started with the compiler
-
增量采用策略
¥Incremental adoption strategies
-
出现问题时进行调试和故障排除
¥Debugging and troubleshooting when things go wrong
-
使用 React 库上的编译器
¥Using the compiler on your React library
React Compiler 的功能是什么?
¥What does React Compiler do?
React Compiler 会在构建时自动优化你的 React 应用。React 通常无需优化就足够快,但有时你需要手动记忆组件和值以保持应用的响应速度。这种手动记忆的方式非常繁琐,容易出错,并且会增加额外的代码维护。React Compiler 会自动为你完成这项优化,让你从这些繁琐的计算中解脱出来,专注于功能构建。
¥React Compiler automatically optimizes your React application at build time. React is often fast enough without optimization, but sometimes you need to manually memoize components and values to keep your app responsive. This manual memoization is tedious, easy to get wrong, and adds extra code to maintain. React Compiler does this optimization automatically for you, freeing you from this mental burden so you can focus on building features.
React Compiler 之前
¥Before React Compiler
不使用编译器时,你需要手动记忆组件和值以优化重新渲染:
¥Without the compiler, you need to manually memoize components and values to optimize re-renders:
import { useMemo, useCallback, memo } from 'react';
const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) {
const processedData = useMemo(() => {
return expensiveProcessing(data);
}, [data]);
const handleClick = useCallback((item) => {
onClick(item.id);
}, [onClick]);
return (
<div>
{processedData.map(item => (
<Item key={item.id} onClick={() => handleClick(item)} />
))}
</div>
);
});
React Compiler 之后
¥After React Compiler
使用 React Compiler,你可以编写相同的代码而无需手动记忆:
¥With React Compiler, you write the same code without manual memoization:
function ExpensiveComponent({ data, onClick }) {
const processedData = expensiveProcessing(data);
const handleClick = (item) => {
onClick(item.id);
};
return (
<div>
{processedData.map(item => (
<Item key={item.id} onClick={() => handleClick(item)} />
))}
</div>
);
}
请参阅 React Compiler Playground 中的此示例
¥*See this example in the React Compiler Playground*
React Compiler 会自动应用等效的优化,确保你的应用仅在必要时重新渲染。
¥React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary.
深入研究
¥What kind of memoization does React Compiler add?
React Compiler 的自动记忆功能主要侧重于提升更新性能(重新渲染现有组件),因此它主要关注以下两种用例:
¥React Compiler’s automatic memoization is primarily focused on improving update performance (re-rendering existing components), so it focuses on these two use cases:
-
跳过组件的级联重新渲染
¥Skipping cascading re-rendering of components
-
重新渲染
<Parent />
会导致其组件树中的许多组件重新渲染,即使只有<Parent />
发生了变化¥Re-rendering
<Parent />
causes many components in its component tree to re-render, even though only<Parent />
has changed
-
-
跳过 React 外部的昂贵计算
¥Skipping expensive calculations from outside of React
-
例如,在需要该数据的组件或钩子内部调用
expensivelyProcessAReallyLargeArrayOfObjects()
¥For example, calling
expensivelyProcessAReallyLargeArrayOfObjects()
inside of your component or hook that needs that data
-
优化重新渲染
¥Optimizing Re-renders
React 可让你根据其当前状态(更具体地说:其属性、状态和上下文)来表达你的 UI。在当前实现中,当组件的状态发生变化时,React 将重新渲染该组件及其所有子组件 - 除非你已使用 useMemo()
、useCallback()
或 React.memo()
应用了某种形式的手动记忆。例如,在以下示例中,每当 <FriendList>
的状态发生变化时,<MessageButton>
都会重新渲染:
¥React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component’s state changes, React will re-render that component and all of its children — unless you have applied some form of manual memoization with useMemo()
, useCallback()
, or React.memo()
. For example, in the following example, <MessageButton>
will re-render whenever <FriendList>
’s state changes:
function FriendList({ friends }) {
const onlineCount = useFriendOnlineCount();
if (friends.length === 0) {
return <NoFriends />;
}
return (
<div>
<span>{onlineCount} online</span>
{friends.map((friend) => (
<FriendListCard key={friend.id} friend={friend} />
))}
<MessageButton />
</div>
);
}
请参阅 React Compiler Playground 中的此示例
¥See this example in the React Compiler Playground
React Compiler 自动应用相当于手动记忆的功能,确保只有应用的相关部分在状态更改时重新渲染,这有时被称为 “细粒度反应性”。在上面的例子中,React Compiler 确定即使 friends
发生变化,<FriendListCard />
的返回值也可以重用,并且可以避免重新创建此 JSX 并避免在计数发生变化时重新渲染 <MessageButton>
。
¥React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as “fine-grained reactivity”. In the above example, React Compiler determines that the return value of <FriendListCard />
can be reused even as friends
changes, and can avoid recreating this JSX and avoid re-rendering <MessageButton>
as the count changes.
昂贵的计算也会被记忆化
¥Expensive calculations also get memoized
React Compiler 还可以自动记忆渲染过程中的复杂计算:
¥React Compiler can also automatically memoize expensive calculations used during rendering:
// **Not** memoized by React Compiler, since this is not a component or hook
function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ }
// Memoized by React Compiler since this is a component
function TableContainer({ items }) {
// This function call would be memoized:
const data = expensivelyProcessAReallyLargeArrayOfObjects(items);
// ...
}
请参阅 React Compiler Playground 中的此示例
¥See this example in the React Compiler Playground
但是,如果 expensivelyProcessAReallyLargeArrayOfObjects
确实是一个昂贵的函数,你可能需要考虑在 React 之外实现自己的记忆,因为:
¥However, if expensivelyProcessAReallyLargeArrayOfObjects
is truly an expensive function, you may want to consider implementing its own memoization outside of React, because:
-
React Compiler 仅记忆 React 组件和钩子,而不是每个函数
¥React Compiler only memoizes React components and hooks, not every function
-
React Compiler 的记忆不会在多个组件或钩子之间共享
¥React Compiler’s memoization is not shared across multiple components or hooks
因此,如果 expensivelyProcessAReallyLargeArrayOfObjects
在许多不同的组件中使用,即使传递了相同的项目,也会重复运行该昂贵的计算。我们建议先使用 profiling,看看它是否真的那么昂贵,然后再使代码变得更复杂。
¥So if expensivelyProcessAReallyLargeArrayOfObjects
was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend profiling first to see if it really is that expensive before making code more complicated.
我应该尝试一下编译器吗?
¥Should I try out the compiler?
我们鼓励每个人都开始使用 React 编译器。虽然编译器目前仍然是 React 的可选附加功能,但将来某些功能可能需要编译器才能完全正常工作。
¥We encourage everyone to start using React Compiler. While the compiler is still an optional addition to React today, in the future some features may require the compiler in order to fully work.
使用安全吗?
¥Is it safe to use?
React Compiler 目前处于 RC 阶段,并已在生产环境中进行了广泛的测试。虽然它已在 Meta 等公司的生产中使用,但将编译器推出到你的应用的生产中将取决于你的代码库的运行状况以及你遵循 React 的规则 的程度。
¥React Compiler is now in RC and has been tested extensively in production. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the Rules of React.
支持哪些构建工具?
¥What build tools are supported?
React Compiler 可以安装在 一些构建工具 的各个版本中,例如 Babel、Vite、Metro 和 Rsbuild。
¥React Compiler can be installed across several build tools such as Babel, Vite, Metro, and Rsbuild.
React Compiler 主要是一个轻量级的 Babel 插件封装器,它围绕核心编译器进行封装,旨在与 Babel 本身解耦。虽然编译器的初始稳定版本仍将主要作为 Babel 插件,但我们正在与 swc 和 oxc 团队合作,为 React Compiler 构建一流的支持,这样你将来就无需将 Babel 重新添加到构建管道中。
¥React Compiler is primarily a light Babel plugin wrapper around the core compiler, which was designed to be decoupled from Babel itself. While the initial stable version of the compiler will remain primarily a Babel plugin, we are working with the swc and oxc teams to build first class support for React Compiler so you won’t have to add Babel back to your build pipelines in the future.
Next.js 用户可以使用 v15.3.1 及更高版本启用由 swc 调用的 React 编译器。
¥Next.js users can enable the swc-invoked React Compiler by using v15.3.1 and up.
我应该如何处理 useMemo、useCallback 和 React.memo?
¥What should I do about useMemo, useCallback, and React.memo?
如果你使用的是 React Compiler,则可以移除 useMemo
、useCallback
和 React.memo
。React Compiler 比这些钩子更精确、更细致地添加了自动记忆功能。如果你选择保留手动 memoization,React Compiler 将分析它们并确定你的手动 memoization 是否与其自动推断的 memoization 匹配。如果没有匹配项,编译器将选择放弃优化该组件。
¥If you are using React Compiler, useMemo
, useCallback
, and React.memo
can be removed. React Compiler adds automatic memoization more precisely and granularly than is possible with these hooks. If you choose to keep manual memoization, React Compiler will analyze them and determine if your manual memoization matches its automatically inferred memoization. If there isn’t a match, the compiler will choose to bail out of optimizing that component.
这样做是出于谨慎,因为手动记忆的常见反模式是用它来确保正确性。这意味着你的应用依赖于被记忆的特定值才能正常工作。例如,为了防止无限循环,你可能已记住一些值以阻止 useEffect
调用触发。这违反了 React 规则,但由于编译器自动删除手动记忆可能会带来潜在危险,因此编译器会选择放弃。你应该手动删除手写的 memoization,并验证应用是否仍按预期运行。
¥This is done out of caution as a common anti-pattern with manual memoization is using it for correctness. This means your app depends on specific values being memoized to work properly. For example, in order to prevent an infinite loop, you may have memoized some values to stop a useEffect
call from firing. This breaks the Rules of React, but since it can potentially be dangerous for the compiler to automatically remove manual memoization, the compiler will just bail out instead. You should manually remove your handwritten memoization and verify that your app still works as expected.
尝试 React Compiler
¥Try React Compiler
本节将帮助你开始使用 React Compiler 并了解如何在你的项目中有效地使用它。
¥This section will help you get started with React Compiler and understand how to use it effectively in your projects.
-
安装 - 安装 React Compiler 并将其配置为你的构建工具
¥**Installation** - Install React Compiler and configure it for your build tools
-
React 版本兼容性 - 支持 React 17、18 和 19
¥**React Version Compatibility** - Support for React 17, 18, and 19
-
配置 - 根据你的特定需求自定义编译器
¥**Configuration** - Customize the compiler for your specific needs
-
增量采用 - 在现有代码库中逐步推广编译器的策略
¥**Incremental Adoption** - Strategies for gradually rolling out the compiler in existing codebases
-
调试和故障排除 - 识别并修复使用编译器时的问题
¥**Debugging and Troubleshooting** - Identify and fix issues when using the compiler
-
编译库 - 发布编译代码的最佳实践
¥**Compiling Libraries** - Best practices for shipping compiled code
-
API 参考 - 所有配置选项的详细文档
¥**API Reference** - Detailed documentation of all configuration options
其他资源
¥Additional resources
除了这些文档之外,我们建议检查 React 编译器工作组 以获取有关编译器的其他信息和讨论。
¥In addition to these docs, we recommend checking the React Compiler Working Group for additional information and discussion about the compiler.