diff --git a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md index ffe761624ba..9ec330e6b2e 100644 --- a/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md +++ b/src/content/blog/2024/02/15/react-labs-what-we-have-been-working-on-february-2024.md @@ -107,7 +107,7 @@ Activity is still under research and our remaining work is to finalize the primi In addition to this update, our team has presented at conferences and made appearances on podcasts to speak more on our work and answer questions. -- [Sathya Gunasekaran](/community/team#sathya-gunasekaran) spoke about the React Compiler at the [React India](https://www.youtube.com/watch?v=kjOacmVsLSE) conference +- [Sathya Gunasekaran](https://github.com/gsathya) spoke about the React Compiler at the [React India](https://www.youtube.com/watch?v=kjOacmVsLSE) conference - [Dan Abramov](/community/team#dan-abramov) gave a talk at [RemixConf](https://www.youtube.com/watch?v=zMf_xeGPn6s) titled “React from Another Dimension” which explores an alternative history of how React Server Components and Actions could have been created diff --git a/src/content/blog/2024/10/21/react-compiler-beta-release.md b/src/content/blog/2024/10/21/react-compiler-beta-release.md index 58e6b24aa49..cd49b6eb2f9 100644 --- a/src/content/blog/2024/10/21/react-compiler-beta-release.md +++ b/src/content/blog/2024/10/21/react-compiler-beta-release.md @@ -72,11 +72,11 @@ Or, if you're using Yarn: yarn add -D eslint-plugin-react-compiler@beta -After installation you can enable the linter by [adding it to your ESLint config](/learn/react-compiler#installing-eslint-plugin-react-compiler). Using the linter helps identify Rules of React breakages, making it easier to adopt the compiler when it's fully released. +After installation you can enable the linter by [adding it to your ESLint config](/learn/react-compiler/installation#eslint-integration). Using the linter helps identify Rules of React breakages, making it easier to adopt the compiler when it's fully released. ## Backwards Compatibility {/*backwards-compatibility*/} -React Compiler produces code that depends on runtime APIs added in React 19, but we've since added support for the compiler to also work with React 17 and 18. If you are not on React 19 yet, in the Beta release you can now try out React Compiler by specifying a minimum `target` in your compiler config, and adding `react-compiler-runtime` as a dependency. [You can find docs on this here](/learn/react-compiler#using-react-compiler-with-react-17-or-18). +React Compiler produces code that depends on runtime APIs added in React 19, but we've since added support for the compiler to also work with React 17 and 18. If you are not on React 19 yet, in the Beta release you can now try out React Compiler by specifying a minimum `target` in your compiler config, and adding `react-compiler-runtime` as a dependency. [You can find docs on this here](/reference/react-compiler/configuration#react-17-18). ## Using React Compiler in libraries {/*using-react-compiler-in-libraries*/} @@ -86,7 +86,7 @@ React Compiler can also be used to compile libraries. Because React Compiler nee Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum `target` and add `react-compiler-runtime` as a direct dependency. The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. -[You can find more docs on this here.](/learn/react-compiler#using-the-compiler-on-libraries) +[You can find more docs on this here.](/reference/react-compiler/compiling-libraries) ## Opening up React Compiler Working Group to everyone {/*opening-up-react-compiler-working-group-to-everyone*/} diff --git a/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md b/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md index e4bb25a4aa6..0f54d02b413 100644 --- a/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md +++ b/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md @@ -2495,7 +2495,7 @@ For example, we can slow down the `default` cross fade animation: ``` -And define `slow-fade` in CSS using [view transition classes](/reference/react/ViewTransition#view-transition-classes): +And define `slow-fade` in CSS using [view transition classes](/reference/react/ViewTransition#view-transition-class): ```css ::view-transition-old(.slow-fade) { diff --git a/src/content/learn/add-react-to-an-existing-project.md b/src/content/learn/add-react-to-an-existing-project.md index 4684fb5b079..5d3d44005a6 100644 --- a/src/content/learn/add-react-to-an-existing-project.md +++ b/src/content/learn/add-react-to-an-existing-project.md @@ -24,7 +24,7 @@ Here's how we recommend to set it up: 2. **Specify `/some-app` as the *base path*** in your framework's configuration (here's how: [Next.js](https://nextjs.org/docs/app/api-reference/config/next-config-js/basePath), [Gatsby](https://www.gatsbyjs.com/docs/how-to/previews-deploys-hosting/path-prefix/)). 3. **Configure your server or a proxy** so that all requests under `/some-app/` are handled by your React app. -This ensures the React part of your app can [benefit from the best practices](/learn/start-a-new-react-project#can-i-use-react-without-a-framework) baked into those frameworks. +This ensures the React part of your app can [benefit from the best practices](/learn/build-a-react-app-from-scratch#consider-using-a-framework) baked into those frameworks. Many React-based frameworks are full-stack and let your React app take advantage of the server. However, you can use the same approach even if you can't or don't want to run JavaScript on the server. In that case, serve the HTML/CSS/JS export ([`next export` output](https://nextjs.org/docs/advanced-features/static-html-export) for Next.js, default for Gatsby) at `/some-app/` instead. diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md deleted file mode 100644 index 9d4e19d210f..00000000000 --- a/src/content/learn/react-compiler.md +++ /dev/null @@ -1,346 +0,0 @@ ---- -title: React Compiler ---- - - -This page will give you an introduction to React Compiler and how to try it out successfully. - - - - -* Getting started with the compiler -* Installing the compiler and ESLint plugin -* Troubleshooting - - - - -React Compiler is a new compiler currently in RC, that we've open sourced to get feedback from the community. We now recommend everyone to try the compiler and provide feedback. - -The latest RC release can be found with the `@rc` tag, and daily experimental releases with `@experimental`. - - -React Compiler is a new compiler that we've open sourced to get feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it. - -eslint-plugin-react-hooks also includes an [ESLint rule](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler. - -The compiler is currently released as `rc`, and is available to try out on React 17+ apps and libraries. To install the RC: - - -{`npm install -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -Or, if you're using Yarn: - - -{`yarn add -D babel-plugin-react-compiler@rc eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions. - -### What does the compiler do? {/*what-does-the-compiler-do*/} - -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. - -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. - - -React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase. - - -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. - - -#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} - -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: - -1. **Skipping cascading re-rendering of components** - * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed -1. **Skipping expensive calculations from outside of React** - * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data - -#### Optimizing Re-renders {/*optimizing-re-renders*/} - -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, `` will re-render whenever ``'s state changes: - -```javascript -function FriendList({ friends }) { - const onlineCount = useFriendOnlineCount(); - if (friends.length === 0) { - return ; - } - return ( -
- {onlineCount} online - {friends.map((friend) => ( - - ))} - -
- ); -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) - -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 `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. - -#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} - -The compiler can also automatically memoize for expensive calculations used during rendering: - -```js -// **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); - // ... -} -``` -[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) - -However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: - -- React Compiler only memoizes React components and hooks, not every function -- React Compiler's memoization is not shared across multiple components or hooks - -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. -
- -### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} - -The 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](/reference/rules). - -**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better. - -## Getting Started {/*getting-started*/} - -In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. - -### Installing eslint-plugin-react-hooks {/*installing-eslint-plugin-react-compiler*/} - -React Compiler also powers an ESLint plugin. You can try it out by installing eslint-plugin-react-hooks@^6.0.0-rc.1. - - -{`npm install -D eslint-plugin-react-hooks@^6.0.0-rc.1`} - - -See our [editor setup](/learn/editor-setup#linting) guide for more details. - -The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. - - -**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler. - - -### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/} - -#### Existing projects {/*existing-projects*/} -The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior. - -For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories: - -```js {3} -const ReactCompilerConfig = { - sources: (filename) => { - return filename.indexOf('src/path/to/dir') !== -1; - }, -}; -``` - -When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app. - -#### New projects {/*new-projects*/} - -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. - -### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/} - -React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17. - - -{`npm install react-compiler-runtime@rc`} - - -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: - -```js {3} -// babel.config.js -const ReactCompilerConfig = { - target: '18' // '17' | '18' | '19' -}; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], - ], - }; -}; -``` - -### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} - -React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm. - -Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary. - -Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation). - -Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify. - -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} - - -{`npm install babel-plugin-react-compiler@rc`} - - -The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. - -After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline: - -```js {7} -// babel.config.js -const ReactCompilerConfig = { /* ... */ }; - -module.exports = function () { - return { - plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... - ], - }; -}; -``` - -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. - -### Vite {/*usage-with-vite*/} - -If you use Vite, you can add the plugin to vite-plugin-react: - -```js {10} -// vite.config.js -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig(() => { - return { - plugins: [ - react({ - babel: { - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], - // ... - }; -}); -``` - -### Next.js {/*usage-with-nextjs*/} - -Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. - -### Remix {/*usage-with-remix*/} -Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: - - -{`npm install vite-plugin-babel`} - - -```js {2,14} -// vite.config.js -import babel from "vite-plugin-babel"; - -const ReactCompilerConfig = { /* ... */ }; - -export default defineConfig({ - plugins: [ - remix({ /* ... */}), - babel({ - filter: /\.[jt]sx?$/, - babelConfig: { - presets: ["@babel/preset-typescript"], // if you use TypeScript - plugins: [ - ["babel-plugin-react-compiler", ReactCompilerConfig], - ], - }, - }), - ], -}); -``` - -### Webpack {/*usage-with-webpack*/} - -A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). - -### Expo {/*usage-with-expo*/} - -Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. - -### Metro (React Native) {/*usage-with-react-native-metro*/} - -React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions. - -### Rspack {/*usage-with-rspack*/} - -Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. - -### Rsbuild {/*usage-with-rsbuild*/} - -Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. - -## Troubleshooting {/*troubleshooting*/} - -To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo. - -You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler). - -### What does the compiler assume? {/*what-does-the-compiler-assume*/} - -React Compiler assumes that your code: - -1. Is valid, semantic JavaScript. -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`. -3. Follows the [Rules of React](https://react.dev/reference/rules). - -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). - -### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/} - -[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. - -### Something is not working after compilation {/*something-is-not-working-after-compilation*/} -If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized. - -Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases. - -If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component). - -```js {2} -function SuspiciousComponent() { - "use no memo"; // opts out this component from being compiled by React Compiler - // ... -} -``` - - -#### `"use no memo"` {/*use-no-memo*/} - -`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is. - -It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive. - - -When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue. - -### Other issues {/*other-issues*/} - -Please see https://github.com/reactwg/react-compiler/discussions/7. diff --git a/src/content/learn/react-compiler/debugging.md b/src/content/learn/react-compiler/debugging.md new file mode 100644 index 00000000000..1883125a6a4 --- /dev/null +++ b/src/content/learn/react-compiler/debugging.md @@ -0,0 +1,93 @@ +--- +title: Debugging and Troubleshooting +--- + + +This guide helps you identify and fix issues when using React Compiler. Learn how to debug compilation problems and resolve common issues. + + + + +* The difference between compiler errors and runtime issues +* Common patterns that break compilation +* Step-by-step debugging workflow + + + +## Understanding Compiler Behavior {/*understanding-compiler-behavior*/} + +React Compiler is designed to handle code that follows the [Rules of React](/reference/rules). When it encounters code that might break these rules, it safely skips optimization rather than risk changing your app's behavior. + +### Compiler Errors vs Runtime Issues {/*compiler-errors-vs-runtime-issues*/} + +**Compiler errors** occur at build time and prevent your code from compiling. These are rare because the compiler is designed to skip problematic code rather than fail. + +**Runtime issues** occur when compiled code behaves differently than expected. Most of the time, if you encounter an issue with React Compiler, it's a runtime issue. This typically happens when your code violates the Rules of React in subtle ways that the compiler couldn't detect, and the compiler mistakenly compiled a component it should have skipped. + +When debugging runtime issues, focus your efforts on finding Rules of React violations in the affected components that were not detected by the ESLint rule. The compiler relies on your code following these rules, and when they're broken in ways it can't detect, that's when runtime problems occur. + + +## Common Breaking Patterns {/*common-breaking-patterns*/} + +One of the main ways React Compiler can break your app is if your code was written to rely on memoization for correctness. This means your app depends on specific values being memoized to work properly. Since the compiler may memoize differently than your manual approach, this can lead to unexpected behavior like effects over-firing, infinite loops, or missing updates. + +Common scenarios where this occurs: + +- **Effects that rely on referential equality** - When effects depend on objects or arrays maintaining the same reference across renders +- **Dependency arrays that need stable references** - When unstable dependencies cause effects to fire too often or create infinite loops +- **Conditional logic based on reference checks** - When code uses referential equality checks for caching or optimization + +## Debugging Workflow {/*debugging-workflow*/} + +Follow these steps when you encounter issues: + +### Compiler Build Errors {/*compiler-build-errors*/} + +If you encounter a compiler error that unexpectedly breaks your build, this is likely a bug in the compiler. Report it to the [facebook/react](https://github.com/facebook/react/issues) repository with: +- The error message +- The code that caused the error +- Your React and compiler versions + +### Runtime Issues {/*runtime-issues*/} + +For runtime behavior issues: + +### 1. Temporarily Disable Compilation {/*temporarily-disable-compilation*/} + +Use `"use no memo"` to isolate whether an issue is compiler-related: + +```js +function ProblematicComponent() { + "use no memo"; // Skip compilation for this component + // ... rest of component +} +``` + +If the issue disappears, it's likely related to a Rules of React violation. + +You can also try removing manual memoization (useMemo, useCallback, memo) from the problematic component to verify that your app works correctly without any memoization. If the bug still occurs when all memoization is removed, you have a Rules of React violation that needs to be fixed. + +### 2. Fix Issues Step by Step {/*fix-issues-step-by-step*/} + +1. Identify the root cause (often memoization-for-correctness) +2. Test after each fix +3. Remove `"use no memo"` once fixed +4. Verify the component shows the ✨ badge in React DevTools + +## Reporting Compiler Bugs {/*reporting-compiler-bugs*/} + +If you believe you've found a compiler bug: + +1. **Verify it's not a Rules of React violation** - Check with ESLint +2. **Create a minimal reproduction** - Isolate the issue in a small example +3. **Test without the compiler** - Confirm the issue only occurs with compilation +4. **File an [issue](https://github.com/facebook/react/issues/new?template=compiler_bug_report.yml)**: + - React and compiler versions + - Minimal reproduction code + - Expected vs actual behavior + - Any error messages + +## Next Steps {/*next-steps*/} + +- Review the [Rules of React](/reference/rules) to prevent issues +- Check the [incremental adoption guide](/learn/react-compiler/incremental-adoption) for gradual rollout strategies \ No newline at end of file diff --git a/src/content/learn/react-compiler/incremental-adoption.md b/src/content/learn/react-compiler/incremental-adoption.md new file mode 100644 index 00000000000..38ffa224ba0 --- /dev/null +++ b/src/content/learn/react-compiler/incremental-adoption.md @@ -0,0 +1,225 @@ +--- +title: Incremental Adoption +--- + + +React Compiler can be adopted incrementally, allowing you to try it on specific parts of your codebase first. This guide shows you how to gradually roll out the compiler in existing projects. + + + + +* Why incremental adoption is recommended +* Using Babel overrides for directory-based adoption +* Using the "use memo" directive for opt-in compilation +* Using the "use no memo" directive to exclude components +* Runtime feature flags with gating +* Monitoring your adoption progress + + + +## Why Incremental Adoption? {/*why-incremental-adoption*/} + +While React Compiler is designed to handle most React code automatically, adopting it incrementally allows you to: + +- Test the compiler on a small portion of your app first +- Identify and fix any Rules of React violations +- Build confidence before expanding to your entire codebase +- Minimize risk in production applications + +## Approaches to Incremental Adoption {/*approaches-to-incremental-adoption*/} + +There are three main approaches to adopt React Compiler incrementally: + +1. **Babel overrides** - Apply the compiler to specific directories +2. **Opt-in with "use memo"** - Only compile components that explicitly opt in +3. **Runtime gating** - Control compilation with feature flags + +All approaches allow you to test the compiler on specific parts of your application before full rollout. + +## Directory-Based Adoption with Babel Overrides {/*directory-based-adoption*/} + +Babel's `overrides` option lets you apply different plugins to different parts of your codebase. This is ideal for gradually adopting React Compiler directory by directory. + +### Basic Configuration {/*basic-configuration*/} + +Start by applying the compiler to a specific directory: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins that apply to all files + ], + overrides: [ + { + test: './src/modern/**/*.{js,jsx,ts,tsx}', + plugins: [ + 'babel-plugin-react-compiler' + ] + } + ] +}; +``` + +### Expanding Coverage {/*expanding-coverage*/} + +As you gain confidence, add more directories: + +```js +// babel.config.js +module.exports = { + plugins: [ + // Global plugins + ], + overrides: [ + { + test: ['./src/modern/**/*.{js,jsx,ts,tsx}', './src/features/**/*.{js,jsx,ts,tsx}'], + plugins: [ + 'babel-plugin-react-compiler' + ] + }, + { + test: './src/legacy/**/*.{js,jsx,ts,tsx}', + plugins: [ + // Different plugins for legacy code + ] + } + ] +}; +``` + +### With Compiler Options {/*with-compiler-options*/} + +You can also configure compiler options per override: + +```js +// babel.config.js +module.exports = { + plugins: [], + overrides: [ + { + test: './src/experimental/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', // Only compile "use memo" components + panicThreshold: 'none' // More permissive for experimental code + }] + ] + }, + { + test: './src/production/**/*.{js,jsx,ts,tsx}', + plugins: [ + ['babel-plugin-react-compiler', { + panicThreshold: 'critical_errors' // Stricter for production code + }] + ] + } + ] +}; +``` + + +## Opt-in Mode with "use memo" {/*opt-in-mode-with-use-memo*/} + +For maximum control, you can use `compilationMode: 'annotation'` to only compile components and hooks that explicitly opt in with the `"use memo"` directive. + + +This approach gives you fine-grained control over individual components and hooks. It's useful when you want to test the compiler on specific components without affecting entire directories. + + +### Annotation Mode Configuration {/*annotation-mode-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation', + }], + ], +}; +``` + +### Using the Directive {/*using-the-directive*/} + +Add `"use memo"` at the beginning of functions you want to compile: + +```js +function TodoList({ todos }) { + "use memo"; // Opt this component into compilation + + const sortedTodos = todos.slice().sort(); + + return ( + + ); +} + +function useSortedData(data) { + "use memo"; // Opt this hook into compilation + + return data.slice().sort(); +} +``` + +With `compilationMode: 'annotation'`, you must: +- Add `"use memo"` to every component you want optimized +- Add `"use memo"` to every custom hook +- Remember to add it to new components + +This gives you precise control over which components are compiled while you evaluate the compiler's impact. + +## Runtime Feature Flags with Gating {/*runtime-feature-flags-with-gating*/} + +The `gating` option enables you to control compilation at runtime using feature flags. This is useful for running A/B tests or gradually rolling out the compiler based on user segments. + +### How Gating Works {/*how-gating-works*/} + +The compiler wraps optimized code in a runtime check. If the gate returns `true`, the optimized version runs. Otherwise, the original code runs. + +### Gating Configuration {/*gating-configuration*/} + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + gating: { + source: 'ReactCompilerFeatureFlags', + importSpecifierName: 'isCompilerEnabled', + }, + }], + ], +}; +``` + +### Implementing the Feature Flag {/*implementing-the-feature-flag*/} + +Create a module that exports your gating function: + +```js +// ReactCompilerFeatureFlags.js +export function isCompilerEnabled() { + // Use your feature flag system + return getFeatureFlag('react-compiler-enabled'); +} +``` + +## Troubleshooting Adoption {/*troubleshooting-adoption*/} + +If you encounter issues during adoption: + +1. Use `"use no memo"` to temporarily exclude problematic components +2. Check the [debugging guide](/learn/react-compiler/debugging) for common issues +3. Fix Rules of React violations identified by the ESLint plugin +4. Consider using `compilationMode: 'annotation'` for more gradual adoption + +## Next Steps {/*next-steps*/} + +- Read the [configuration guide](/reference/react-compiler/configuration) for more options +- Learn about [debugging techniques](/learn/react-compiler/debugging) +- Check the [API reference](/reference/react-compiler/configuration) for all compiler options \ No newline at end of file diff --git a/src/content/learn/react-compiler/index.md b/src/content/learn/react-compiler/index.md new file mode 100644 index 00000000000..480187ed5e6 --- /dev/null +++ b/src/content/learn/react-compiler/index.md @@ -0,0 +1,33 @@ +--- +title: React Compiler +--- + +## Introduction {/*introduction*/} + +Learn [what React Compiler does](/learn/react-compiler/introduction) and how it automatically optimizes your React application by handling memoization for you, eliminating the need for manual `useMemo`, `useCallback`, and `React.memo`. + +## Installation {/*installation*/} + +Get started with [installing React Compiler](/learn/react-compiler/installation) and learn how to configure it with your build tools. + + +## Incremental Adoption {/*incremental-adoption*/} + +Learn [strategies for gradually adopting React Compiler](/learn/react-compiler/incremental-adoption) in your existing codebase if you're not ready to enable it everywhere yet. + +## Debugging and Troubleshooting {/*debugging-and-troubleshooting*/} + +When things don't work as expected, use our [debugging guide](/learn/react-compiler/debugging) to understand the difference between compiler errors and runtime issues, identify common breaking patterns, and follow a systematic debugging workflow. + +## Configuration and Reference {/*configuration-and-reference*/} + +For detailed configuration options and API reference: + +- [Configuration Options](/reference/react-compiler/configuration) - All compiler configuration options including React version compatibility +- [Directives](/reference/react-compiler/directives) - Function-level compilation control +- [Compiling Libraries](/reference/react-compiler/compiling-libraries) - Shipping pre-compiled libraries + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/react-compiler/installation.md b/src/content/learn/react-compiler/installation.md new file mode 100644 index 00000000000..3606c9c6dd7 --- /dev/null +++ b/src/content/learn/react-compiler/installation.md @@ -0,0 +1,258 @@ +--- +title: Installation +--- + + +This guide will help you install and configure React Compiler in your React application. + + + + +* How to install React Compiler +* Basic configuration for different build tools +* How to verify your setup is working + + + +## Prerequisites {/*prerequisites*/} + +React Compiler is designed to work best with React 19, but it also supports React 17 and 18. Learn more about [React version compatibility](/reference/react-compiler/target). + + +React Compiler is currently in RC. Install it using the `@rc` tag to get the latest release candidate version. + + +## Installation {/*installation*/} + +Install React Compiler as a `devDependency`: + + +npm install -D babel-plugin-react-compiler@rc + + +Or with Yarn: + + +yarn add -D babel-plugin-react-compiler@rc + + +Or with pnpm: + + +pnpm install -D babel-plugin-react-compiler@rc + + +## Basic Setup {/*basic-setup*/} + +React Compiler is designed to work by default without any configuration. However, if you need to configure it in special circumstances (for example, to target React versions below 19), refer to the [compiler options reference](/reference/react-compiler/configuration). + +The setup process depends on your build tool. React Compiler includes a Babel plugin that integrates with your build pipeline. + + +React Compiler must run **first** in your Babel plugin pipeline. The compiler needs the original source information for proper analysis, so it must process your code before other transformations. + + +### Babel {/*babel*/} + +Create or update your `babel.config.js`: + +```js {3} +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', // must run first! + // ... other plugins + ], + // ... other config +}; +``` + +### Vite {/*vite*/} + +If you use Vite, you can add the plugin to vite-plugin-react: + +```js {3,9} +// vite.config.js +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react({ + babel: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +Alternatively, if you prefer a separate Babel plugin for Vite: + + +npm install -D vite-plugin-babel + + +```js {2,11} +// vite.config.js +import babel from 'vite-plugin-babel'; +import { defineConfig } from 'vite'; +import react from '@vitejs/plugin-react'; + +export default defineConfig({ + plugins: [ + react(), + babel({ + babelConfig: { + plugins: ['babel-plugin-react-compiler'], + }, + }), + ], +}); +``` + +### Next.js {/*usage-with-nextjs*/} + +Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information. + +### React Router {/*usage-with-react-router*/} +Install `vite-plugin-babel`, and add the compiler's Babel plugin to it: + + +{`npm install vite-plugin-babel`} + + +```js {3-4,16} +// vite.config.js +import { defineConfig } from "vite"; +import babel from "vite-plugin-babel"; +import { reactRouter } from "@react-router/dev/vite"; + +const ReactCompilerConfig = { /* ... */ }; + +export default defineConfig({ + plugins: [ + reactRouter(), + babel({ + filter: /\.[jt]sx?$/, + babelConfig: { + presets: ["@babel/preset-typescript"], // if you use TypeScript + plugins: [ + ["babel-plugin-react-compiler", ReactCompilerConfig], + ], + }, + }), + ], +}); +``` + +### Webpack {/*usage-with-webpack*/} + +A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). + +### Expo {/*usage-with-expo*/} + +Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps. + +### Metro (React Native) {/*usage-with-react-native-metro*/} + +React Native uses Babel via Metro, so refer to the [Usage with Babel](#babel) section for installation instructions. + +### Rspack {/*usage-with-rspack*/} + +Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps. + +### Rsbuild {/*usage-with-rsbuild*/} + +Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps. + + +## ESLint Integration {/*eslint-integration*/} + +React Compiler includes an ESLint rule that helps identify code that can't be optimized. When the ESLint rule reports an error, it means the compiler will skip optimizing that specific component or hook. This is safe: the compiler will continue optimizing other parts of your codebase. You don't need to fix all violations immediately. Address them at your own pace to gradually increase the number of optimized components. + +Install the ESLint plugin: + + +npm install -D eslint-plugin-react-hooks@rc + + +Then enable the compiler rule in your ESLint configuration: + +```js {3} +// .eslintrc.js +module.exports = { + rules: { + 'react-hooks/react-compiler': 'error', + }, +}; +``` + +The ESLint rule will: +- Identify violations of the [Rules of React](/reference/rules) +- Show which components can't be optimized +- Provide helpful error messages for fixing issues + +## Verify Your Setup {/*verify-your-setup*/} + +After installation, verify that React Compiler is working correctly. + +### Check React DevTools {/*check-react-devtools*/} + +Components optimized by React Compiler will show a "Memo ✨" badge in React DevTools: + +1. Install the [React Developer Tools](/learn/react-developer-tools) browser extension +2. Open your app in development mode +3. Open React DevTools +4. Look for the ✨ emoji next to component names + +If the compiler is working: +- Components will show a "Memo ✨" badge in React DevTools +- Expensive calculations will be automatically memoized +- No manual `useMemo` is required + +### Check Build Output {/*check-build-output*/} + +You can also verify the compiler is running by checking your build output. The compiled code will include automatic memoization logic that the compiler adds automatically. + +```js +import { c as _c } from "react/compiler-runtime"; +export default function MyApp() { + const $ = _c(1); + let t0; + if ($[0] === Symbol.for("react.memo_cache_sentinel")) { + t0 =
Hello World
; + $[0] = t0; + } else { + t0 = $[0]; + } + return t0; +} + +``` + +## Troubleshooting {/*troubleshooting*/} + +### Opting out specific components {/*opting-out-specific-components*/} + +If a component is causing issues after compilation, you can temporarily opt it out using the `"use no memo"` directive: + +```js +function ProblematicComponent() { + "use no memo"; + // Component code here +} +``` + +This tells the compiler to skip optimization for this specific component. You should fix the underlying issue and remove the directive once resolved. + +For more troubleshooting help, see the [debugging guide](/learn/react-compiler/debugging). + +## Next Steps {/*next-steps*/} + +Now that you have React Compiler installed, learn more about: + +- [React version compatibility](/reference/react-compiler/target) for React 17 and 18 +- [Configuration options](/reference/react-compiler/configuration) to customize the compiler +- [Incremental adoption strategies](/learn/react-compiler/incremental-adoption) for existing codebases +- [Debugging techniques](/learn/react-compiler/debugging) for troubleshooting issues +- [Compiling Libraries guide](/reference/react-compiler/compiling-libraries) for compiling your React library \ No newline at end of file diff --git a/src/content/learn/react-compiler/introduction.md b/src/content/learn/react-compiler/introduction.md new file mode 100644 index 00000000000..440c66ab61c --- /dev/null +++ b/src/content/learn/react-compiler/introduction.md @@ -0,0 +1,176 @@ +--- +title: Introduction +--- + + +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](/reference/rules), so you don't need to rewrite any code to use it. + + + + +* What React Compiler does +* Getting started with the compiler +* Incremental adoption strategies +* Debugging and troubleshooting when things go wrong +* Using the compiler on your React library + + + + +React Compiler is currently in Release Candidate (RC). We now recommend everyone to try the compiler and provide feedback. The latest RC release can be found with the `@rc` tag. + + +## What does React Compiler do? {/*what-does-react-compiler-do*/} + +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. + +### Before React Compiler {/*before-react-compiler*/} + +Without the compiler, you need to manually memoize components and values to optimize re-renders: + +```js +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 ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +}); +``` + +### After React Compiler {/*after-react-compiler*/} + +With React Compiler, you write the same code without manual memoization: + +```js +function ExpensiveComponent({ data, onClick }) { + const processedData = expensiveProcessing(data); + + const handleClick = (item) => { + onClick(item.id); + }; + + return ( +
+ {processedData.map(item => ( + handleClick(item)} /> + ))} +
+ ); +} +``` + +_[See this example in the React Compiler Playground](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAogB4AOCmYeAbggMIQC2Fh1OAFMEQCYBDHAIA0RQowA2eOAGsiAXwCURYAB1iROITA4iFGBERgwCPgBEhAogF4iCStVoMACoeO1MAcy6DhSgG4NDSItHT0ACwFMPkkmaTlbIi48HAQWFRsAPlUQ0PFMKRlZFLSWADo8PkC8hSDMPJgEHFhiLjzQgB4+eiyO-OADIwQTM0thcpYBClL02xz2zXz8zoBJMqJZBABPG2BU9Mq+BQKiuT2uTJyomLizkoOMk4B6PqX8pSUFfs7nnro3qEapgFCAFEA)_ + +React Compiler automatically applies the equivalent optimizations, ensuring your app only re-renders when necessary. + + +#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/} + +React Compiler's automatic memoization is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases: + +1. **Skipping cascading re-rendering of components** + * Re-rendering `` causes many components in its component tree to re-render, even though only `` has changed +1. **Skipping expensive calculations from outside of React** + * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data + +#### Optimizing Re-renders {/*optimizing-re-renders*/} + +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, `` will re-render whenever ``'s state changes: + +```javascript +function FriendList({ friends }) { + const onlineCount = useFriendOnlineCount(); + if (friends.length === 0) { + return ; + } + return ( +
+ {onlineCount} online + {friends.map((friend) => ( + + ))} + +
+ ); +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA) + +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 `` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes. + +#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/} + +React Compiler can also automatically memoize expensive calculations used during rendering: + +```js +// **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); + // ... +} +``` +[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA) + +However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because: + +- React Compiler only memoizes React components and hooks, not every function +- React Compiler's memoization is not shared across multiple components or hooks + +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](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. +
+ +## Should I try out the compiler? {/*should-i-try-out-the-compiler*/} + +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? {/*is-it-safe-to-use*/} + +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](/reference/rules). + +## What build tools are supported? {/*what-build-tools-are-supported*/} + +React Compiler can be installed across [several build tools](/learn/react-compiler/installation) such as Babel, Vite, Metro, and Rsbuild. + +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](https://github.com/oxc-project/oxc/issues/10048) 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 users can enable the swc-invoked React Compiler by using [v15.3.1](https://github.com/vercel/next.js/releases/tag/v15.3.1) and up. + +## What should I do about useMemo, useCallback, and React.memo? {/*what-should-i-do-about-usememo-usecallback-and-reactmemo*/} + +If you are using React Compiler, [`useMemo`](/reference/react/useMemo), [`useCallback`](/reference/react/useCallback), and [`React.memo`](/reference/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. + +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. + +## Try React Compiler {/*try-react-compiler*/} + +This section will help you get started with React Compiler and understand how to use it effectively in your projects. + +* **[Installation](/learn/react-compiler/installation)** - Install React Compiler and configure it for your build tools +* **[React Version Compatibility](/reference/react-compiler/target)** - Support for React 17, 18, and 19 +* **[Configuration](/reference/react-compiler/configuration)** - Customize the compiler for your specific needs +* **[Incremental Adoption](/learn/react-compiler/incremental-adoption)** - Strategies for gradually rolling out the compiler in existing codebases +* **[Debugging and Troubleshooting](/learn/react-compiler/debugging)** - Identify and fix issues when using the compiler +* **[Compiling Libraries](/reference/react-compiler/compiling-libraries)** - Best practices for shipping compiled code +* **[API Reference](/reference/react-compiler/configuration)** - Detailed documentation of all configuration options + +## Additional resources {/*additional-resources*/} + +In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler. + diff --git a/src/content/learn/synchronizing-with-effects.md b/src/content/learn/synchronizing-with-effects.md index 1150751618b..c0ad34709b9 100644 --- a/src/content/learn/synchronizing-with-effects.md +++ b/src/content/learn/synchronizing-with-effects.md @@ -732,7 +732,7 @@ Writing `fetch` calls inside Effects is a [popular way to fetch data](https://ww This list of downsides is not specific to React. It applies to fetching data on mount with any library. Like with routing, data fetching is not trivial to do well, so we recommend the following approaches: -- **If you use a [framework](/learn/start-a-new-react-project#production-grade-react-frameworks), use its built-in data fetching mechanism.** Modern React frameworks have integrated data fetching mechanisms that are efficient and don't suffer from the above pitfalls. +- **If you use a [framework](/learn/start-a-new-react-project#full-stack-frameworks), use its built-in data fetching mechanism.** Modern React frameworks have integrated data fetching mechanisms that are efficient and don't suffer from the above pitfalls. - **Otherwise, consider using or building a client-side cache.** Popular open source solutions include [React Query](https://tanstack.com/query/latest), [useSWR](https://swr.vercel.app/), and [React Router 6.4+.](https://beta.reactrouter.com/en/main/start/overview) You can build your own solution too, in which case you would use Effects under the hood, but add logic for deduplicating requests, caching responses, and avoiding network waterfalls (by preloading data or hoisting data requirements to routes). You can continue fetching data directly in Effects if neither of these approaches suit you. diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md index bf7483d1cf2..c348e649662 100644 --- a/src/content/learn/typescript.md +++ b/src/content/learn/typescript.md @@ -13,14 +13,14 @@ TypeScript is a popular way to add type definitions to JavaScript codebases. Out * [TypeScript with React Components](/learn/typescript#typescript-with-react-components) * [Examples of typing with Hooks](/learn/typescript#example-hooks) -* [Common types from `@types/react`](/learn/typescript/#useful-types) -* [Further learning locations](/learn/typescript/#further-learning) +* [Common types from `@types/react`](/learn/typescript#useful-types) +* [Further learning locations](/learn/typescript#further-learning) ## Installation {/*installation*/} -All [production-grade React frameworks](/learn/start-a-new-react-project#production-grade-react-frameworks) offer support for using TypeScript. Follow the framework specific guide for installation: +All [production-grade React frameworks](/learn/start-a-new-react-project#full-stack-frameworks) offer support for using TypeScript. Follow the framework specific guide for installation: - [Next.js](https://nextjs.org/docs/app/building-your-application/configuring/typescript) - [Remix](https://remix.run/docs/en/1.19.2/guides/typescript) @@ -124,7 +124,7 @@ The type describing your component's props can be as simple or as complex as you ## Example Hooks {/*example-hooks*/} -The type definitions from `@types/react` include types for the built-in Hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get [inferred types](https://www.typescriptlang.org/docs/handbook/type-inference.html) a lot of the time and ideally do not need to handle the minutiae of providing the types. +The type definitions from `@types/react` include types for the built-in Hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get [inferred types](https://www.typescriptlang.org/docs/handbook/type-inference.html) a lot of the time and ideally do not need to handle the minutiae of providing the types. However, we can look at a few examples of how to provide types for Hooks. @@ -139,7 +139,7 @@ const [enabled, setEnabled] = useState(false); This will assign the type of `boolean` to `enabled`, and `setEnabled` will be a function accepting either a `boolean` argument, or a function that returns a `boolean`. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the `useState` call: -```ts +```ts // Explicitly set the type to "boolean" const [enabled, setEnabled] = useState(false); ``` @@ -174,7 +174,7 @@ The [`useReducer` Hook](/reference/react/useReducer) is a more complex Hook that import {useReducer} from 'react'; interface State { - count: number + count: number }; type CounterAction = @@ -284,7 +284,7 @@ export default App = AppTSX; -This technique works when you have a default value which makes sense - but there are occasionally cases when you do not, and in those cases `null` can feel reasonable as a default value. However, to allow the type-system to understand your code, you need to explicitly set `ContextShape | null` on the `createContext`. +This technique works when you have a default value which makes sense - but there are occasionally cases when you do not, and in those cases `null` can feel reasonable as a default value. However, to allow the type-system to understand your code, you need to explicitly set `ContextShape | null` on the `createContext`. This causes the issue that you need to eliminate the `| null` in the type for context consumers. Our recommendation is to have the Hook do a runtime check for it's existence and throw an error when not present: @@ -329,6 +329,12 @@ function MyComponent() { ### `useMemo` {/*typing-usememo*/} + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useMemo` calls. You can use the compiler to handle memoization automatically. + + + The [`useMemo`](/reference/react/useMemo) Hooks will create/re-access a memorized value from a function call, re-running the function only when dependencies passed as the 2nd parameter are changed. The result of calling the Hook is inferred from the return value from the function in the first parameter. You can be more explicit by providing a type argument to the Hook. ```ts @@ -339,6 +345,12 @@ const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]); ### `useCallback` {/*typing-usecallback*/} + + +[React Compiler](/learn/react-compiler) automatically memoizes values and functions, reducing the need for manual `useCallback` calls. You can use the compiler to handle memoization automatically. + + + The [`useCallback`](/reference/react/useCallback) provide a stable reference to a function as long as the dependencies passed into the second parameter are the same. Like `useMemo`, the function's type is inferred from the return value of the function in the first parameter, and you can be more explicit by providing a type argument to the Hook. @@ -350,7 +362,7 @@ const handleClick = useCallback(() => { When working in TypeScript strict mode `useCallback` requires adding types for the parameters in your callback. This is because the type of the callback is inferred from the return value of the function, and without parameters the type cannot be fully understood. -Depending on your code-style preferences, you could use the `*EventHandler` functions from the React types to provide the type for the event handler at the same time as defining the callback: +Depending on your code-style preferences, you could use the `*EventHandler` functions from the React types to provide the type for the event handler at the same time as defining the callback: ```ts import { useState, useCallback } from 'react'; @@ -361,7 +373,7 @@ export default function Form() { const handleChange = useCallback>((event) => { setValue(event.currentTarget.value); }, [setValue]) - + return ( <> @@ -433,7 +445,7 @@ interface ModalRendererProps { } ``` -Note, that you cannot use TypeScript to describe that the children are a certain type of JSX elements, so you cannot use the type-system to describe a component which only accepts `
  • ` children. +Note, that you cannot use TypeScript to describe that the children are a certain type of JSX elements, so you cannot use the type-system to describe a component which only accepts `
  • ` children. You can see an example of both `React.ReactNode` and `React.ReactElement` with the type-checker in [this TypeScript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wChSB6CxYmAOmXRgDkIATJOdNJMGAZzgwAFpxAR+8YADswAVwGkZMJFEzpOjDKw4AFHGEEBvUnDhphwADZsi0gFw0mDWjqQBuUgF9yaCNMlENzgAXjgACjADfkctFnYkfQhDAEpQgD44AB42YAA3dKMo5P46C2tbJGkvLIpcgt9-QLi3AEEwMFCItJDMrPTTbIQ3dKywdIB5aU4kKyQQKpha8drhhIGzLLWODbNs3b3s8YAxKBQAcwXpAThMaGWDvbH0gFloGbmrgQfBzYpd1YjQZbEYARkB6zMwO2SHSAAlZlYIBCdtCRkZpHIrFYahQYQD8UYYFA5EhcfjyGYqHAXnJAsIUHlOOUbHYhMIIHJzsI0Qk4P9SLUBuRqXEXEwAKKfRZcNA8PiCfxWACecAAUgBlAAacFm80W-CU11U6h4TgwUv11yShjgJjMLMqDnN9Dilq+nh8pD8AXgCHdMrCkWisVoAet0R6fXqhWKhjKllZVVxMcavpd4Zg7U6Qaj+2hmdG4zeRF10uu-Aeq0LBfLMEe-V+T2L7zLVu+FBWLdLeq+lc7DYFf39deFVOotMCACNOCh1dq219a+30uC8YWoZsRyuEdjkevR8uvoVMdjyTWt4WiSSydXD4NqZP4AymeZE072ZzuUeZQKheQgA). diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md index a009793ab6c..88e490e1aea 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -26,7 +26,7 @@ There are two common cases in which you don't need Effects: * **You don't need Effects to transform data for rendering.** For example, let's say you want to filter a list before displaying it. You might feel tempted to write an Effect that updates a state variable when the list changes. However, this is inefficient. When you update the state, React will first call your component functions to calculate what should be on the screen. Then React will ["commit"](/learn/render-and-commit) these changes to the DOM, updating the screen. Then React will run your Effects. If your Effect *also* immediately updates the state, this restarts the whole process from scratch! To avoid the unnecessary render passes, transform all the data at the top level of your components. That code will automatically re-run whenever your props or state change. * **You don't need Effects to handle user events.** For example, let's say you want to send an `/api/buy` POST request and show a notification when the user buys a product. In the Buy button click event handler, you know exactly what happened. By the time an Effect runs, you don't know *what* the user did (for example, which button was clicked). This is why you'll usually handle user events in the corresponding event handlers. -You *do* need Effects to [synchronize](/learn/synchronizing-with-effects#what-are-effects-and-how-are-they-different-from-events) with external systems. For example, you can write an Effect that keeps a jQuery widget synchronized with the React state. You can also fetch data with Effects: for example, you can synchronize the search results with the current search query. Keep in mind that modern [frameworks](/learn/start-a-new-react-project#production-grade-react-frameworks) provide more efficient built-in data fetching mechanisms than writing Effects directly in your components. +You *do* need Effects to [synchronize](/learn/synchronizing-with-effects#what-are-effects-and-how-are-they-different-from-events) with external systems. For example, you can write an Effect that keeps a jQuery widget synchronized with the React state. You can also fetch data with Effects: for example, you can synchronize the search results with the current search query. Keep in mind that modern [frameworks](/learn/start-a-new-react-project#full-stack-frameworks) provide more efficient built-in data fetching mechanisms than writing Effects directly in your components. To help you gain the right intuition, let's look at some common concrete examples! @@ -95,6 +95,12 @@ Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook: + + +[React Compiler](/learn/react-compiler) can automatically memoize expensive calculations for you, eliminating the need for manual `useMemo` in many cases. + + + ```js {5-8} import { useMemo, useState } from 'react'; @@ -751,7 +757,7 @@ This ensures that when your Effect fetches data, all responses except the last r Handling race conditions is not the only difficulty with implementing data fetching. You might also want to think about caching responses (so that the user can click Back and see the previous screen instantly), how to fetch data on the server (so that the initial server-rendered HTML contains the fetched content instead of a spinner), and how to avoid network waterfalls (so that a child can fetch data without waiting for every parent). -**These issues apply to any UI library, not just React. Solving them is not trivial, which is why modern [frameworks](/learn/start-a-new-react-project#production-grade-react-frameworks) provide more efficient built-in data fetching mechanisms than fetching data in Effects.** +**These issues apply to any UI library, not just React. Solving them is not trivial, which is why modern [frameworks](/learn/start-a-new-react-project#full-stack-frameworks) provide more efficient built-in data fetching mechanisms than fetching data in Effects.** If you don't use a framework (and don't want to build your own) but would like to make data fetching from Effects more ergonomic, consider extracting your fetching logic into a custom Hook like in this example: diff --git a/src/content/reference/react-compiler/compilationMode.md b/src/content/reference/react-compiler/compilationMode.md new file mode 100644 index 00000000000..5513d1c6a68 --- /dev/null +++ b/src/content/reference/react-compiler/compilationMode.md @@ -0,0 +1,201 @@ +--- +title: compilationMode +--- + + + +The `compilationMode` option controls how the React Compiler selects which functions to compile. + + + +```js +{ + compilationMode: 'infer' // or 'annotation', 'syntax', 'all' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `compilationMode` {/*compilationmode*/} + +Controls the strategy for determining which functions the React Compiler will optimize. + +#### Type {/*type*/} + +``` +'infer' | 'syntax' | 'annotation' | 'all' +``` + +#### Default value {/*default-value*/} + +`'infer'` + +#### Options {/*options*/} + +- **`'infer'`** (default): The compiler uses intelligent heuristics to identify React components and hooks: + - Functions explicitly annotated with `"use memo"` directive + - Functions that are named like components (PascalCase) or hooks (`use` prefix) AND create JSX and/or call other hooks + +- **`'annotation'`**: Only compile functions explicitly marked with the `"use memo"` directive. Ideal for incremental adoption. + +- **`'syntax'`**: Only compile components and hooks that use Flow's [component](https://flow.org/en/docs/react/component-syntax/) and [hook](https://flow.org/en/docs/react/hook-syntax/) syntax. + +- **`'all'`**: Compile all top-level functions. Not recommended as it may compile non-React functions. + +#### Caveats {/*caveats*/} + +- The `'infer'` mode requires functions to follow React naming conventions to be detected +- Using `'all'` mode may negatively impact performance by compiling utility functions +- The `'syntax'` mode requires Flow and won't work with TypeScript +- Regardless of mode, functions with `"use no memo"` directive are always skipped + +--- + +## Usage {/*usage*/} + +### Default inference mode {/*default-inference-mode*/} + +The default `'infer'` mode works well for most codebases that follow React conventions: + +```js +{ + compilationMode: 'infer' +} +``` + +With this mode, these functions will be compiled: + +```js +// ✅ Compiled: Named like a component + returns JSX +function Button(props) { + return ; +} + +// ✅ Compiled: Named like a hook + calls hooks +function useCounter() { + const [count, setCount] = useState(0); + return [count, setCount]; +} + +// ✅ Compiled: Explicit directive +function expensiveCalculation(data) { + "use memo"; + return data.reduce(/* ... */); +} + +// ❌ Not compiled: Not a component/hook pattern +function calculateTotal(items) { + return items.reduce((a, b) => a + b, 0); +} +``` + +### Incremental adoption with annotation mode {/*incremental-adoption*/} + +For gradual migration, use `'annotation'` mode to only compile marked functions: + +```js +{ + compilationMode: 'annotation' +} +``` + +Then explicitly mark functions to compile: + +```js +// Only this function will be compiled +function ExpensiveList(props) { + "use memo"; + return ( +
      + {props.items.map(item => ( +
    • {item.name}
    • + ))} +
    + ); +} + +// This won't be compiled without the directive +function NormalComponent(props) { + return
    {props.content}
    ; +} +``` + +### Using Flow syntax mode {/*flow-syntax-mode*/} + +If your codebase uses Flow instead of TypeScript: + +```js +{ + compilationMode: 'syntax' +} +``` + +Then use Flow's component syntax: + +```js +// Compiled: Flow component syntax +component Button(label: string) { + return ; +} + +// Compiled: Flow hook syntax +hook useCounter(initial: number) { + const [count, setCount] = useState(initial); + return [count, setCount]; +} + +// Not compiled: Regular function syntax +function helper(data) { + return process(data); +} +``` + +### Opting out specific functions {/*opting-out*/} + +Regardless of compilation mode, use `"use no memo"` to skip compilation: + +```js +function ComponentWithSideEffects() { + "use no memo"; // Prevent compilation + + // This component has side effects that shouldn't be memoized + logToAnalytics('component_rendered'); + + return
    Content
    ; +} +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Component not being compiled in infer mode {/*component-not-compiled-infer*/} + +In `'infer'` mode, ensure your component follows React conventions: + +```js +// ❌ Won't be compiled: lowercase name +function button(props) { + return ; +} + +// ✅ Will be compiled: PascalCase name +function Button(props) { + return ; +} + +// ❌ Won't be compiled: doesn't create JSX or call hooks +function useData() { + return window.localStorage.getItem('data'); +} + +// ✅ Will be compiled: calls a hook +function useData() { + const [data] = useState(() => window.localStorage.getItem('data')); + return data; +} +``` diff --git a/src/content/reference/react-compiler/compiling-libraries.md b/src/content/reference/react-compiler/compiling-libraries.md new file mode 100644 index 00000000000..f09ffcb725f --- /dev/null +++ b/src/content/reference/react-compiler/compiling-libraries.md @@ -0,0 +1,106 @@ +--- +title: Compiling Libraries +--- + + +This guide helps library authors understand how to use React Compiler to ship optimized library code to their users. + + + + +## Why Ship Compiled Code? {/*why-ship-compiled-code*/} + +As a library author, you can compile your library code before publishing to npm. This provides several benefits: + +- **Performance improvements for all users** - Your library users get optimized code even if they aren't using React Compiler yet +- **No configuration required by users** - The optimizations work out of the box +- **Consistent behavior** - All users get the same optimized version regardless of their build setup + +## Setting Up Compilation {/*setting-up-compilation*/} + +Add React Compiler to your library's build process: + + +npm install -D babel-plugin-react-compiler@rc + + +Configure your build tool to compile your library. For example, with Babel: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler', + ], + // ... other config +}; +``` + +## Backwards Compatibility {/*backwards-compatibility*/} + +If your library supports React versions below 19, you'll need additional configuration: + +### 1. Install the runtime package {/*install-runtime-package*/} + +We recommend installing react-compiler-runtime as a direct dependency: + + +npm install react-compiler-runtime@rc + + +```json +{ + "dependencies": { + "react-compiler-runtime": "^19.1.0-rc.2" + }, + "peerDependencies": { + "react": "^17.0.0 || ^18.0.0 || ^19.0.0" + } +} +``` + +### 2. Configure the target version {/*configure-target-version*/} + +Set the minimum React version your library supports: + +```js +{ + target: '17', // Minimum supported React version +} +``` + +## Testing Strategy {/*testing-strategy*/} + +Test your library both with and without compilation to ensure compatibility. Run your existing test suite against the compiled code, and also create a separate test configuration that bypasses the compiler. This helps catch any issues that might arise from the compilation process and ensures your library works correctly in all scenarios. + +## Troubleshooting {/*troubleshooting*/} + +### Library doesn't work with older React versions {/*library-doesnt-work-with-older-react-versions*/} + +If your compiled library throws errors in React 17 or 18: + +1. Verify you've installed `react-compiler-runtime` as a dependency +2. Check that your `target` configuration matches your minimum supported React version +3. Ensure the runtime package is included in your published bundle + +### Compilation conflicts with other Babel plugins {/*compilation-conflicts-with-other-babel-plugins*/} + +Some Babel plugins may conflict with React Compiler: + +1. Place `babel-plugin-react-compiler` early in your plugin list +2. Disable conflicting optimizations in other plugins +3. Test your build output thoroughly + +### Runtime module not found {/*runtime-module-not-found*/} + +If users see "Cannot find module 'react-compiler-runtime'": + +1. Ensure the runtime is listed in `dependencies`, not `devDependencies` +2. Check that your bundler includes the runtime in the output +3. Verify the package is published to npm with your library + +## Next Steps {/*next-steps*/} + +- Learn about [debugging techniques](/learn/react-compiler/debugging) for compiled code +- Check the [configuration options](/reference/react-compiler/configuration) for all compiler options +- Explore [compilation modes](/reference/react-compiler/compilationMode) for selective optimization \ No newline at end of file diff --git a/src/content/reference/react-compiler/configuration.md b/src/content/reference/react-compiler/configuration.md new file mode 100644 index 00000000000..f38f1afc0a4 --- /dev/null +++ b/src/content/reference/react-compiler/configuration.md @@ -0,0 +1,151 @@ +--- +title: Configuration +--- + + + +This page lists all configuration options available in React Compiler. + + + + + +For most apps, the default options should work out of the box. If you have a special need, you can use these advanced options. + + + +```js +// babel.config.js +module.exports = { + plugins: [ + [ + 'babel-plugin-react-compiler', { + // compiler options + } + ] + ] +}; +``` + +--- + +## Compilation Control {/*compilation-control*/} + +These options control *what* the compiler optimizes and *how* it selects components and hooks to compile. + +* [`compilationMode`](/reference/react-compiler/compilationMode) controls the strategy for selecting functions to compile (e.g., all functions, only annotated ones, or intelligent detection). + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + +--- + +## Version Compatibility {/*version-compatibility*/} + +React version configuration ensures the compiler generates code compatible with your React version. + +[`target`](/reference/react-compiler/target) specifies which React version you're using (17, 18, or 19). + +```js +// For React 18 projects +{ + target: '18' // Also requires react-compiler-runtime package +} +``` + +--- + +## Error Handling {/*error-handling*/} + +These options control how the compiler responds to code that doesn't follow the [Rules of React](/reference/rules). + +[`panicThreshold`](/reference/react-compiler/panicThreshold) determines whether to fail the build or skip problematic components. + +```js +// Recommended for production +{ + panicThreshold: 'none' // Skip components with errors instead of failing the build +} +``` + +--- + +## Debugging {/*debugging*/} + +Logging and analysis options help you understand what the compiler is doing. + +[`logger`](/reference/react-compiler/logger) provides custom logging for compilation events. + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileSuccess') { + console.log('Compiled:', filename); + } + } + } +} +``` + +--- + +## Feature Flags {/*feature-flags*/} + +Conditional compilation lets you control when optimized code is used. + +[`gating`](/reference/react-compiler/gating) enables runtime feature flags for A/B testing or gradual rollouts. + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'isCompilerEnabled' + } +} +``` + +--- + +## Common Configuration Patterns {/*common-patterns*/} + +### Default configuration {/*default-configuration*/} + +For most React 19 applications, the compiler works without configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + 'babel-plugin-react-compiler' + ] +}; +``` + +### React 17/18 projects {/*react-17-18*/} + +Older React versions need the runtime package and target configuration: + +```bash +npm install react-compiler-runtime@rc +``` + +```js +{ + target: '18' // or '17' +} +``` + +### Incremental adoption {/*incremental-adoption*/} + +Start with specific directories and expand gradually: + +```js +{ + compilationMode: 'annotation' // Only compile "use memo" functions +} +``` + diff --git a/src/content/reference/react-compiler/directives.md b/src/content/reference/react-compiler/directives.md new file mode 100644 index 00000000000..705d0f6209e --- /dev/null +++ b/src/content/reference/react-compiler/directives.md @@ -0,0 +1,198 @@ +--- +title: Directives +--- + + +React Compiler directives are special string literals that control whether specific functions are compiled. + + +```js +function MyComponent() { + "use memo"; // Opt this component into compilation + return
    {/* ... */}
    ; +} +``` + + + +--- + +## Overview {/*overview*/} + +React Compiler directives provide fine-grained control over which functions are optimized by the compiler. They are string literals placed at the beginning of a function body or at the top of a module. + +### Available directives {/*available-directives*/} + +* **[`"use memo"`](/reference/react-compiler/directives/use-memo)** - Opts a function into compilation +* **[`"use no memo"`](/reference/react-compiler/directives/use-no-memo)** - Opts a function out of compilation + +### Quick comparison {/*quick-comparison*/} + +| Directive | Purpose | When to use | +|-----------|---------|-------------| +| [`"use memo"`](/reference/react-compiler/directives/use-memo) | Force compilation | When using `annotation` mode or to override `infer` mode heuristics | +| [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) | Prevent compilation | Debugging issues or working with incompatible code | + +--- + +## Usage {/*usage*/} + +### Function-level directives {/*function-level*/} + +Place directives at the beginning of a function to control its compilation: + +```js +// Opt into compilation +function OptimizedComponent() { + "use memo"; + return
    This will be optimized
    ; +} + +// Opt out of compilation +function UnoptimizedComponent() { + "use no memo"; + return
    This won't be optimized
    ; +} +``` + +### Module-level directives {/*module-level*/} + +Place directives at the top of a file to affect all functions in that module: + +```js +// At the very top of the file +"use memo"; + +// All functions in this file will be compiled +function Component1() { + return
    Compiled
    ; +} + +function Component2() { + return
    Also compiled
    ; +} + +// Can be overridden at function level +function Component3() { + "use no memo"; // This overrides the module directive + return
    Not compiled
    ; +} +``` + +### Compilation modes interaction {/*compilation-modes*/} + +Directives behave differently depending on your [`compilationMode`](/reference/react-compiler/compilationMode): + +* **`annotation` mode**: Only functions with `"use memo"` are compiled +* **`infer` mode**: Compiler decides what to compile, directives override decisions +* **`all` mode**: Everything is compiled, `"use no memo"` can exclude specific functions + +--- + +## Best practices {/*best-practices*/} + +### Use directives sparingly {/*use-sparingly*/} + +Directives are escape hatches. Prefer configuring the compiler at the project level: + +```js +// ✅ Good - project-wide configuration +{ + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'infer' + }] + ] +} + +// ⚠️ Use directives only when needed +function SpecialCase() { + "use no memo"; // Document why this is needed + // ... +} +``` + +### Document directive usage {/*document-usage*/} + +Always explain why a directive is used: + +```js +// ✅ Good - clear explanation +function DataGrid() { + "use no memo"; // TODO: Remove after fixing issue with dynamic row heights (JIRA-123) + // Complex grid implementation +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### Plan for removal {/*plan-removal*/} + +Opt-out directives should be temporary: + +1. Add the directive with a TODO comment +2. Create a tracking issue +3. Fix the underlying problem +4. Remove the directive + +```js +function TemporaryWorkaround() { + "use no memo"; // TODO: Remove after upgrading ThirdPartyLib to v2.0 + return ; +} +``` + +--- + +## Common patterns {/*common-patterns*/} + +### Gradual adoption {/*gradual-adoption*/} + +When adopting the React Compiler in a large codebase: + +```js +// Start with annotation mode +{ + compilationMode: 'annotation' +} + +// Opt in stable components +function StableComponent() { + "use memo"; + // Well-tested component +} + +// Later, switch to infer mode and opt out problematic ones +function ProblematicComponent() { + "use no memo"; // Fix issues before removing + // ... +} +``` + + +--- + +## Troubleshooting {/*troubleshooting*/} + +For specific issues with directives, see the troubleshooting sections in: + +* [`"use memo"` troubleshooting](/reference/react-compiler/directives/use-memo#troubleshooting) +* [`"use no memo"` troubleshooting](/reference/react-compiler/directives/use-no-memo#troubleshooting) + +### Common issues {/*common-issues*/} + +1. **Directive ignored**: Check placement (must be first) and spelling +2. **Compilation still happens**: Check `ignoreUseNoForget` setting +3. **Module directive not working**: Ensure it's before all imports + +--- + +## See also {/*see-also*/} + +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure how the compiler chooses what to optimize +* [`Configuration`](/reference/react-compiler/configuration) - Full compiler configuration options +* [React Compiler documentation](https://react.dev/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-memo.md b/src/content/reference/react-compiler/directives/use-memo.md new file mode 100644 index 00000000000..431862682f1 --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-memo.md @@ -0,0 +1,157 @@ +--- +title: "use memo" +titleForTitleTag: "'use memo' directive" +--- + + + +`"use memo"` marks a function for React Compiler optimization. + + + + + +In most cases, you don't need `"use memo"`. It's primarily needed in `annotation` mode where you must explicitly mark functions for optimization. In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + + + + + +--- + +## Reference {/*reference*/} + +### `"use memo"` {/*use-memo*/} + +Add `"use memo"` at the beginning of a function to mark it for React Compiler optimization. + +```js {1} +function MyComponent() { + "use memo"; + // ... +} +``` + +When a function contains `"use memo"`, the React Compiler will analyze and optimize it during build time. The compiler will automatically memoize values and components to prevent unnecessary re-computations and re-renders. + +#### Caveats {/*caveats*/} + +* `"use memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use memo"`. +* Only the first directive in a function is processed; additional directives are ignored. +* The effect of the directive depends on your [`compilationMode`](/reference/react-compiler/compilationMode) setting. + +### How `"use memo"` marks functions for optimization {/*how-use-memo-marks*/} + +In a React app that uses the React Compiler, functions are analyzed at build time to determine if they can be optimized. By default, the compiler automatically infers which components to memoize, but this can depend on your [`compilationMode`](/reference/react-compiler/compilationMode) setting if you've set it. + +`"use memo"` explicitly marks a function for optimization, overriding the default behavior: + +* In `annotation` mode: Only functions with `"use memo"` are optimized +* In `infer` mode: The compiler uses heuristics, but `"use memo"` forces optimization +* In `all` mode: Everything is optimized by default, making `"use memo"` redundant + +The directive creates a clear boundary in your codebase between optimized and non-optimized code, giving you fine-grained control over the compilation process. + +### When to use `"use memo"` {/*when-to-use*/} + +You should consider using `"use memo"` when: + +#### You're using annotation mode {/*annotation-mode-use*/} +In `compilationMode: 'annotation'`, the directive is required for any function you want optimized: + +```js +// ✅ This component will be optimized +function OptimizedList() { + "use memo"; + // ... +} + +// ❌ This component won't be optimized +function SimpleWrapper() { + // ... +} +``` + +#### You're gradually adopting React Compiler {/*gradual-adoption*/} +Start with `annotation` mode and selectively optimize stable components: + +```js +// Start by optimizing leaf components +function Button({ onClick, children }) { + "use memo"; + // ... +} + +// Gradually move up the tree as you verify behavior +function ButtonGroup({ buttons }) { + "use memo"; + // ... +} +``` + +--- + +## Usage {/*usage*/} + +### Working with different compilation modes {/*compilation-modes*/} + +The behavior of `"use memo"` changes based on your compiler configuration: + +```js +// babel.config.js +module.exports = { + plugins: [ + ['babel-plugin-react-compiler', { + compilationMode: 'annotation' // or 'infer' or 'all' + }] + ] +}; +``` + +#### Annotation mode {/*annotation-mode-example*/} +```js +// ✅ Optimized with "use memo" +function ProductCard({ product }) { + "use memo"; + // ... +} + +// ❌ Not optimized (no directive) +function ProductList({ products }) { + // ... +} +``` + +#### Infer mode (default) {/*infer-mode-example*/} +```js +// Automatically memoized because this is named like a Component +function ComplexDashboard({ data }) { + // ... +} + +// Skipped: Is not named like a Component +function simpleDisplay({ text }) { + // ... +} +``` + +In `infer` mode, the compiler automatically detects components and hooks by their naming patterns (PascalCase for components, `use` prefix for hooks). If a component or hook isn't being compiled in `infer` mode, you should fix its naming convention rather than forcing compilation with `"use memo"`. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Verifying optimization {/*verifying-optimization*/} + +To confirm your component is being optimized: + +1. Check the compiled output in your build +2. Use React DevTools to check for Memo ✨ badge + +### See also {/*see-also*/} + +* [`"use no memo"`](/reference/react-compiler/directives/use-no-memo) - Opt out of compilation +* [`compilationMode`](/reference/react-compiler/compilationMode) - Configure compilation behavior +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/directives/use-no-memo.md b/src/content/reference/react-compiler/directives/use-no-memo.md new file mode 100644 index 00000000000..e6c419bc66c --- /dev/null +++ b/src/content/reference/react-compiler/directives/use-no-memo.md @@ -0,0 +1,147 @@ +--- +title: "use no memo" +titleForTitleTag: "'use no memo' directive" +--- + + + +`"use no memo"` prevents a function from being optimized by React Compiler. + + + + + +--- + +## Reference {/*reference*/} + +### `"use no memo"` {/*use-no-memo*/} + +Add `"use no memo"` at the beginning of a function to prevent React Compiler optimization. + +```js {1} +function MyComponent() { + "use no memo"; + // ... +} +``` + +When a function contains `"use no memo"`, the React Compiler will skip it entirely during optimization. This is useful as a temporary escape hatch when debugging or when dealing with code that doesn't work correctly with the compiler. + +#### Caveats {/*caveats*/} + +* `"use no memo"` must be at the very beginning of a function body, before any imports or other code (comments are OK). +* The directive must be written with double or single quotes, not backticks. +* The directive must exactly match `"use no memo"` or its alias `"use no forget"`. +* This directive takes precedence over all compilation modes and other directives. +* It's intended as a temporary debugging tool, not a permanent solution. + +### How `"use no memo"` opts-out of optimization {/*how-use-no-memo-opts-out*/} + +React Compiler analyzes your code at build time to apply optimizations. `"use no memo"` creates an explicit boundary that tells the compiler to skip a function entirely. + +This directive takes precedence over all other settings: +* In `all` mode: The function is skipped despite the global setting +* In `infer` mode: The function is skipped even if heuristics would optimize it + +The compiler treats these functions as if the React Compiler wasn't enabled, leaving them exactly as written. + +### When to use `"use no memo"` {/*when-to-use*/} + +`"use no memo"` should be used sparingly and temporarily. Common scenarios include: + +#### Debugging compiler issues {/*debugging-compiler*/} +When you suspect the compiler is causing issues, temporarily disable optimization to isolate the problem: + +```js +function ProblematicComponent({ data }) { + "use no memo"; // TODO: Remove after fixing issue #123 + + // Rules of React violations that weren't statically detected + // ... +} +``` + +#### Third-party library integration {/*third-party*/} +When integrating with libraries that might not be compatible with the compiler: + +```js +function ThirdPartyWrapper() { + "use no memo"; + + useThirdPartyHook(); // Has side effects that compiler might optimize incorrectly + // ... +} +``` + +--- + +## Usage {/*usage*/} + +The `"use no memo"` directive is placed at the beginning of a function body to prevent React Compiler from optimizing that function: + +```js +function MyComponent() { + "use no memo"; + // Function body +} +``` + +The directive can also be placed at the top of a file to affect all functions in that module: + +```js +"use no memo"; + +// All functions in this file will be skipped by the compiler +``` + +`"use no memo"` at the function level overrides the module level directive. + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Directive not preventing compilation {/*not-preventing*/} + +If `"use no memo"` isn't working: + +```js +// ❌ Wrong - directive after code +function Component() { + const data = getData(); + "use no memo"; // Too late! +} + +// ✅ Correct - directive first +function Component() { + "use no memo"; + const data = getData(); +} +``` + +Also check: +* Spelling - must be exactly `"use no memo"` +* Quotes - must use single or double quotes, not backticks + +### Best practices {/*best-practices*/} + +**Always document why** you're disabling optimization: + +```js +// ✅ Good - clear explanation and tracking +function DataProcessor() { + "use no memo"; // TODO: Remove after fixing rule of react violation + // ... +} + +// ❌ Bad - no explanation +function Mystery() { + "use no memo"; + // ... +} +``` + +### See also {/*see-also*/} + +* [`"use memo"`](/reference/react-compiler/directives/use-memo) - Opt into compilation +* [React Compiler](/learn/react-compiler) - Getting started guide \ No newline at end of file diff --git a/src/content/reference/react-compiler/gating.md b/src/content/reference/react-compiler/gating.md new file mode 100644 index 00000000000..2959c49fa29 --- /dev/null +++ b/src/content/reference/react-compiler/gating.md @@ -0,0 +1,139 @@ +--- +title: gating +--- + + + +The `gating` option enables conditional compilation, allowing you to control when optimized code is used at runtime. + + + +```js +{ + gating: { + source: 'my-feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `gating` {/*gating*/} + +Configures runtime feature flag gating for compiled functions. + +#### Type {/*type*/} + +``` +{ + source: string; + importSpecifierName: string; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Properties {/*properties*/} + +- **`source`**: Module path to import the feature flag from +- **`importSpecifierName`**: Name of the exported function to import + +#### Caveats {/*caveats*/} + +- The gating function must return a boolean +- Both compiled and original versions increase bundle size +- The import is added to every file with compiled functions + +--- + +## Usage {/*usage*/} + +### Basic feature flag setup {/*basic-setup*/} + +1. Create a feature flag module: + +```js +// src/utils/feature-flags.js +export function shouldUseCompiler() { + // your logic here + return Math.random() < 0.5; +} +``` + +2. Configure the compiler: + +```js +{ + gating: { + source: './src/utils/feature-flags', + importSpecifierName: 'shouldUseCompiler' + } +} +``` + +3. The compiler generates gated code: + +```js +// Input +function Button(props) { + return ; +} + +// Output (simplified) +import { shouldUseCompiler } from './src/utils/feature-flags'; + +const Button = shouldUseCompiler() + ? function Button_optimized(props) { /* compiled version */ } + : function Button_original(props) { /* original version */ }; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Feature flag not working {/*flag-not-working*/} + +Verify your flag module exports the correct function: + +```js +// ❌ Wrong: Default export +export default function shouldUseCompiler() { + return true; +} + +// ✅ Correct: Named export matching importSpecifierName +export function shouldUseCompiler() { + return true; +} +``` + +### Import errors {/*import-errors*/} + +Ensure the source path is correct: + +```js +// ❌ Wrong: Relative to babel.config.js +{ + source: './src/flags', + importSpecifierName: 'flag' +} + +// ✅ Correct: Module resolution path +{ + source: '@myapp/feature-flags', + importSpecifierName: 'flag' +} + +// ✅ Also correct: Absolute path from project root +{ + source: './src/utils/flags', + importSpecifierName: 'flag' +} +``` diff --git a/src/content/reference/react-compiler/logger.md b/src/content/reference/react-compiler/logger.md new file mode 100644 index 00000000000..41e2a1da064 --- /dev/null +++ b/src/content/reference/react-compiler/logger.md @@ -0,0 +1,118 @@ +--- +title: logger +--- + + + +The `logger` option provides custom logging for React Compiler events during compilation. + + + +```js +{ + logger: { + logEvent(filename, event) { + console.log(`[Compiler] ${event.kind}: ${filename}`); + } + } +} +``` + + + +--- + +## Reference {/*reference*/} + +### `logger` {/*logger*/} + +Configures custom logging to track compiler behavior and debug issues. + +#### Type {/*type*/} + +``` +{ + logEvent: (filename: string | null, event: LoggerEvent) => void; +} | null +``` + +#### Default value {/*default-value*/} + +`null` + +#### Methods {/*methods*/} + +- **`logEvent`**: Called for each compiler event with the filename and event details + +#### Event types {/*event-types*/} + +- **`CompileSuccess`**: Function successfully compiled +- **`CompileError`**: Function skipped due to errors +- **`CompileDiagnostic`**: Non-fatal diagnostic information +- **`CompileSkip`**: Function skipped for other reasons +- **`PipelineError`**: Unexpected compilation error +- **`Timing`**: Performance timing information + +#### Caveats {/*caveats*/} + +- Event structure may change between versions +- Large codebases generate many log entries + +--- + +## Usage {/*usage*/} + +### Basic logging {/*basic-logging*/} + +Track compilation success and failures: + +```js +{ + logger: { + logEvent(filename, event) { + switch (event.kind) { + case 'CompileSuccess': { + console.log(`✅ Compiled: ${filename}`); + break; + } + case 'CompileError': { + console.log(`❌ Skipped: ${filename}`); + break; + } + default: {} + } + } + } +} +``` + +### Detailed error logging {/*detailed-error-logging*/} + +Get specific information about compilation failures: + +```js +{ + logger: { + logEvent(filename, event) { + if (event.kind === 'CompileError') { + console.error(`\nCompilation failed: ${filename}`); + console.error(`Reason: ${event.detail.reason}`); + + if (event.detail.description) { + console.error(`Details: ${event.detail.description}`); + } + + if (event.detail.loc) { + const { line, column } = event.detail.loc.start; + console.error(`Location: Line ${line}, Column ${column}`); + } + + if (event.detail.suggestions) { + console.error('Suggestions:', event.detail.suggestions); + } + } + } + } +} +``` + diff --git a/src/content/reference/react-compiler/panicThreshold.md b/src/content/reference/react-compiler/panicThreshold.md new file mode 100644 index 00000000000..e20f5c0c508 --- /dev/null +++ b/src/content/reference/react-compiler/panicThreshold.md @@ -0,0 +1,87 @@ +--- +title: panicThreshold +--- + + + +The `panicThreshold` option controls how the React Compiler handles errors during compilation. + + + +```js +{ + panicThreshold: 'none' // Recommended +} +``` + + + +--- + +## Reference {/*reference*/} + +### `panicThreshold` {/*panicthreshold*/} + +Determines whether compilation errors should fail the build or skip optimization. + +#### Type {/*type*/} + +``` +'none' | 'critical_errors' | 'all_errors' +``` + +#### Default value {/*default-value*/} + +`'none'` + +#### Options {/*options*/} + +- **`'none'`** (default, recommended): Skip components that can't be compiled and continue building +- **`'critical_errors'`**: Fail the build only on critical compiler errors +- **`'all_errors'`**: Fail the build on any compiler diagnostic + +#### Caveats {/*caveats*/} + +- Production builds should always use `'none'` +- Build failures prevent your application from building +- The compiler automatically detects and skips problematic code with `'none'` +- Higher thresholds are only useful during development for debugging + +--- + +## Usage {/*usage*/} + +### Production configuration (recommended) {/*production-configuration*/} + +For production builds, always use `'none'`. This is the default value: + +```js +{ + panicThreshold: 'none' +} +``` + +This ensures: +- Your build never fails due to compiler issues +- Components that can't be optimized run normally +- Maximum components get optimized +- Stable production deployments + +### Development debugging {/*development-debugging*/} + +Temporarily use stricter thresholds to find issues: + +```js +const isDevelopment = process.env.NODE_ENV === 'development'; + +{ + panicThreshold: isDevelopment ? 'critical_errors' : 'none', + logger: { + logEvent(filename, event) { + if (isDevelopment && event.kind === 'CompileError') { + // ... + } + } + } +} +``` \ No newline at end of file diff --git a/src/content/reference/react-compiler/target.md b/src/content/reference/react-compiler/target.md new file mode 100644 index 00000000000..381748513d9 --- /dev/null +++ b/src/content/reference/react-compiler/target.md @@ -0,0 +1,148 @@ +--- +title: target +--- + + + +The `target` option specifies which React version the compiler should generate code for. + + + +```js +{ + target: '19' // or '18', '17' +} +``` + + + +--- + +## Reference {/*reference*/} + +### `target` {/*target*/} + +Configures the React version compatibility for the compiled output. + +#### Type {/*type*/} + +``` +'17' | '18' | '19' +``` + +#### Default value {/*default-value*/} + +`'19'` + +#### Valid values {/*valid-values*/} + +- **`'19'`**: Target React 19 (default). No additional runtime required. +- **`'18'`**: Target React 18. Requires `react-compiler-runtime` package. +- **`'17'`**: Target React 17. Requires `react-compiler-runtime` package. + +#### Caveats {/*caveats*/} + +- Always use string values, not numbers (e.g., `'17'` not `17`) +- Don't include patch versions (e.g., use `'18'` not `'18.2.0'`) +- React 19 includes built-in compiler runtime APIs +- React 17 and 18 require installing `react-compiler-runtime@rc` + +--- + +## Usage {/*usage*/} + +### Targeting React 19 (default) {/*targeting-react-19*/} + +For React 19, no special configuration is needed: + +```js +{ + // defaults to target: '19' +} +``` + +The compiler will use React 19's built-in runtime APIs: + +```js +// Compiled output uses React 19's native APIs +import { c as _c } from 'react/compiler-runtime'; +``` + +### Targeting React 17 or 18 {/*targeting-react-17-or-18*/} + +For React 17 and React 18 projects, you need two steps: + +1. Install the runtime package: + +```bash +npm install react-compiler-runtime@rc +``` + +2. Configure the target: + +```js +// For React 18 +{ + target: '18' +} + +// For React 17 +{ + target: '17' +} +``` + +The compiler will use the polyfill runtime for both versions: + +```js +// Compiled output uses the polyfill +import { c as _c } from 'react-compiler-runtime'; +``` + +--- + +## Troubleshooting {/*troubleshooting*/} + +### Runtime errors about missing compiler runtime {/*missing-runtime*/} + +If you see errors like "Cannot find module 'react/compiler-runtime'": + +1. Check your React version: + ```bash + npm why react + ``` + +2. If using React 17 or 18, install the runtime: + ```bash + npm install react-compiler-runtime@rc + ``` + +3. Ensure your target matches your React version: + ```js + { + target: '18' // Must match your React major version + } + ``` + +### Runtime package not working {/*runtime-not-working*/} + +Ensure the runtime package is: + +1. Installed in your project (not globally) +2. Listed in your `package.json` dependencies +3. The correct version (`@rc` tag) +4. Not in `devDependencies` (it's needed at runtime) + +### Checking compiled output {/*checking-output*/} + +To verify the correct runtime is being used, note the different import (`react/compiler-runtime` for builtin, `react-compiler-runtime` standalone package for 17/18): + +```js +// For React 19 (built-in runtime) +import { c } from 'react/compiler-runtime' +// ^ + +// For React 17/18 (polyfill runtime) +import { c } from 'react-compiler-runtime' +// ^ +``` \ No newline at end of file diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md index cb533ec78ba..da12ee27c05 100644 --- a/src/content/reference/react-dom/client/createRoot.md +++ b/src/content/reference/react-dom/client/createRoot.md @@ -209,7 +209,7 @@ When your HTML is empty, the user sees a blank page until the app's JavaScript c
    ``` -This can feel very slow! To solve this, you can generate the initial HTML from your components [on the server or during the build.](/reference/react-dom/server) Then your visitors can read text, see images, and click links before any of the JavaScript code loads. We recommend [using a framework](/learn/start-a-new-react-project#production-grade-react-frameworks) that does this optimization out of the box. Depending on when it runs, this is called *server-side rendering (SSR)* or *static site generation (SSG).* +This can feel very slow! To solve this, you can generate the initial HTML from your components [on the server or during the build.](/reference/react-dom/server) Then your visitors can read text, see images, and click links before any of the JavaScript code loads. We recommend [using a framework](/learn/start-a-new-react-project#full-stack-frameworks) that does this optimization out of the box. Depending on when it runs, this is called *server-side rendering (SSR)* or *static site generation (SSG).* diff --git a/src/content/reference/react-dom/client/index.md b/src/content/reference/react-dom/client/index.md index 89f48212fad..a0042202395 100644 --- a/src/content/reference/react-dom/client/index.md +++ b/src/content/reference/react-dom/client/index.md @@ -4,7 +4,7 @@ title: Client React DOM APIs -The `react-dom/client` APIs let you render React components on the client (in the browser). These APIs are typically used at the top level of your app to initialize your React tree. A [framework](/learn/start-a-new-react-project#production-grade-react-frameworks) may call them for you. Most of your components don't need to import or use them. +The `react-dom/client` APIs let you render React components on the client (in the browser). These APIs are typically used at the top level of your app to initialize your React tree. A [framework](/learn/start-a-new-react-project#full-stack-frameworks) may call them for you. Most of your components don't need to import or use them. diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md index 9d15332139d..f6e73b7c8bc 100644 --- a/src/content/reference/react-dom/components/common.md +++ b/src/content/reference/react-dom/components/common.md @@ -916,7 +916,7 @@ export default function Form() { -Read more about [manipulating DOM with refs](/learn/manipulating-the-dom-with-refs) and [check out more examples.](/reference/react/useRef#examples-dom) +Read more about [manipulating DOM with refs](/learn/manipulating-the-dom-with-refs) and [check out more examples.](/reference/react/useRef#usage) For more advanced use cases, the `ref` attribute also accepts a [callback function.](#ref-callback) diff --git a/src/content/reference/react-dom/components/form.md b/src/content/reference/react-dom/components/form.md index 115e6a4cd20..356637bcdcb 100644 --- a/src/content/reference/react-dom/components/form.md +++ b/src/content/reference/react-dom/components/form.md @@ -36,7 +36,7 @@ To create interactive controls for submitting information, render the [built-in #### Props {/*props*/} -`
    ` supports all [common element props.](/reference/react-dom/components/common#props) +`` supports all [common element props.](/reference/react-dom/components/common#common-props) [`action`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form#action): a URL or function. When a URL is passed to `action` the form will behave like the HTML form component. When a function is passed to `action` the function will handle the form submission. The function passed to `action` may be async and will be called with a single argument containing the [form data](https://developer.mozilla.org/en-US/docs/Web/API/FormData) of the submitted form. The `action` prop can be overridden by a `formAction` attribute on a `