Skip to content

Commit 8fbbe81

Browse files
committed
Flesh out compiler intro section more
This upstreams some of the [introduction post](reactwg/react-compiler#5) into the docs since this knowledge is quite fundamental to understanding the compiler, and it's confusing to not have it linked in the canonical source for the docs ghstack-source-id: 5ccb767 Pull Request resolved: #6895
1 parent 80d30d7 commit 8fbbe81

1 file changed

Lines changed: 73 additions & 3 deletions

File tree

src/content/learn/react-compiler.md

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,81 @@ The compiler also includes an [eslint plugin](#installing-eslint-plugin-react-co
3030

3131
### What does the compiler do? {/*what-does-the-compiler-do*/}
3232

33-
The compiler understands your code at a deep level through its understanding of plain JavaScript semantics and the [Rules of React](/reference/rules). This allows it to add automatic optimizations to your code.
33+
In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes.
3434

35-
You may be familiar today with manual memoization through [`useMemo`](/reference/react/useMemo), [`useCallback`](/reference/react/useCallback), and [`React.memo`](/reference/react/memo). The compiler can automatically do this for you, if your code follows the [Rules of React](/reference/rules). If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code.
35+
The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code.
3636

37-
If your codebase is already very well memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand.
37+
If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand.
38+
39+
<DeepDive>
40+
#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/}
41+
42+
The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases:
43+
44+
1. **Skipping cascading re-rendering of components**
45+
* Re-rendering `<Parent />` causes many components in its component tree to re-render, even though only `<Parent />` has changed
46+
1. **Skipping expensive calculations from outside of React**
47+
* For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data
48+
49+
#### Optimizing Re-renders {/*optimizing-re-renders*/}
50+
51+
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:
52+
53+
```javascript
54+
function FriendList({ friends }) {
55+
const onlineCount = useFriendOnlineCount();
56+
if (friends.length === 0) {
57+
return <NoFriends />;
58+
}
59+
return (
60+
<div>
61+
<span>{onlineCount} online</span>
62+
{friends.map((friend) => (
63+
<FriendListCard key={friend.id} friend={friend} />
64+
))}
65+
<MessageButton />
66+
</div>
67+
);
68+
}
69+
```
70+
[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA)
71+
72+
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.
73+
74+
#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/}
75+
76+
The compiler can also automatically memoize for expensive calculations used during rendering:
77+
78+
```js
79+
// **Not** memoized by React Compiler, since this is not a component or hook
80+
function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ }
81+
82+
// Memoized by React Compiler since this is a component
83+
function TableContainer({ items }) {
84+
// This function call would be memoized:
85+
const data = expensivelyProcessAReallyLargeArrayOfObjects(items);
86+
// ...
87+
}
88+
```
89+
[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA)
90+
91+
However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because:
92+
93+
- React Compiler only memoizes React components and hooks, not every function
94+
- React Compiler's memoization is not shared across multiple components or hooks
95+
96+
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](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated.
97+
</DeepDive>
98+
99+
### What does the compiler assume? {/*what-does-the-compiler-assume*/}
100+
101+
React Compiler assumes that your code:
102+
103+
1. Is valid, semantic JavaScript
104+
2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`
105+
3. Follows the [Rules of React](https://react.dev/reference/rules)
106+
107+
React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler).
38108

39109
### Should I try out the compiler? {/*should-i-try-out-the-compiler*/}
40110

0 commit comments

Comments
 (0)