From 2bd6189d240703990a3c7452fd4124ba48e9f0d2 Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Tue, 15 Oct 2024 03:56:53 +0900 Subject: [PATCH 1/3] Capitalize "Effect" (#7211) --- src/content/reference/react/useReducer.md | 2 +- src/content/reference/react/useState.md | 2 +- src/content/reference/react/useTransition.md | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/content/reference/react/useReducer.md b/src/content/reference/react/useReducer.md index cfd0fb856..ed3dc68c2 100644 --- a/src/content/reference/react/useReducer.md +++ b/src/content/reference/react/useReducer.md @@ -52,7 +52,7 @@ function MyComponent() { #### Caveats {/*caveats*/} * `useReducer` is a Hook, so you can only call it **at the top level of your component** or your own Hooks. You can't call it inside loops or conditions. If you need that, extract a new component and move the state into it. -* The `dispatch` function has a stable identity, so you will often see it omitted from effect dependencies, but including it will not cause the effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) +* The `dispatch` function has a stable identity, so you will often see it omitted from Effect dependencies, but including it will not cause the Effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) * In Strict Mode, React will **call your reducer and initializer twice** in order to [help you find accidental impurities.](#my-reducer-or-initializer-function-runs-twice) This is development-only behavior and does not affect production. If your reducer and initializer are pure (as they should be), this should not affect your logic. The result from one of the calls is ignored. --- diff --git a/src/content/reference/react/useState.md b/src/content/reference/react/useState.md index 4aa9d5911..23db1aae5 100644 --- a/src/content/reference/react/useState.md +++ b/src/content/reference/react/useState.md @@ -85,7 +85,7 @@ function handleClick() { * React [batches state updates.](/learn/queueing-a-series-of-state-updates) It updates the screen **after all the event handlers have run** and have called their `set` functions. This prevents multiple re-renders during a single event. In the rare case that you need to force React to update the screen earlier, for example to access the DOM, you can use [`flushSync`.](/reference/react-dom/flushSync) -* The `set` function has a stable identity, so you will often see it omitted from effect dependencies, but including it will not cause the effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) +* The `set` function has a stable identity, so you will often see it omitted from Effect dependencies, but including it will not cause the Effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) * Calling the `set` function *during rendering* is only allowed from within the currently rendering component. React will discard its output and immediately attempt to render it again with the new state. This pattern is rarely needed, but you can use it to **store information from the previous renders**. [See an example below.](#storing-information-from-previous-renders) diff --git a/src/content/reference/react/useTransition.md b/src/content/reference/react/useTransition.md index 5066fe637..b6dcb3c73 100644 --- a/src/content/reference/react/useTransition.md +++ b/src/content/reference/react/useTransition.md @@ -80,7 +80,7 @@ function TabContainer() { * The function you pass to `startTransition` must be synchronous. React immediately executes this function, marking all state updates that happen while it executes as Transitions. If you try to perform more state updates later (for example, in a timeout), they won't be marked as Transitions. -* The `startTransition` function has a stable identity, so you will often see it omitted from effect dependencies, but including it will not cause the effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) +* The `startTransition` function has a stable identity, so you will often see it omitted from Effect dependencies, but including it will not cause the Effect to fire. If the linter lets you omit a dependency without errors, it is safe to do. [Learn more about removing Effect dependencies.](/learn/removing-effect-dependencies#move-dynamic-objects-and-functions-inside-your-effect) * A state update marked as a Transition will be interrupted by other state updates. For example, if you update a chart component inside a Transition, but then start typing into an input while the chart is in the middle of a re-render, React will restart the rendering work on the chart component after handling the input update. From ee094926d54eef5cec54c9299842eeb822c7859b Mon Sep 17 00:00:00 2001 From: lauren Date: Thu, 17 Oct 2024 16:55:24 -0400 Subject: [PATCH 2/3] [compiler] Move React 17/18 section to its own subheading (#7230) Currently it's a little hidden, let's move it to its own subheading for more prominence --- src/content/learn/react-compiler.md | 54 +++++++++++++---------------- 1 file changed, 25 insertions(+), 29 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 5afaa4cf5..08e2e5672 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -192,61 +192,63 @@ export default function App() { 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*/} -## Usage {/*installation*/} - -### Babel {/*usage-with-babel*/} +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 babel-plugin-react-compiler@experimental +npm install react-compiler-runtime@experimental -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: +You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: -```js {7} +```js {3} // babel.config.js -const ReactCompilerConfig = { /* ... */ }; +const ReactCompilerConfig = { + target: '18' // '17' | '18' | '19' +}; module.exports = function () { return { plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first! - // ... + ['babel-plugin-react-compiler', ReactCompilerConfig], ], }; }; ``` -`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis. +#### New projects {/*new-projects*/} -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. +If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. + +## Usage {/*installation*/} + +### Babel {/*usage-with-babel*/} -npm install react-compiler-runtime@experimental +npm install babel-plugin-react-compiler@experimental -You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: +The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. -```js {3} +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 = { - target: '18' // '17' | '18' | '19' -}; +const ReactCompilerConfig = { /* ... */ }; module.exports = function () { return { plugins: [ - ['babel-plugin-react-compiler', ReactCompilerConfig], + ['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: @@ -392,12 +394,6 @@ To report issues, please first create a minimal repro on the [React Compiler Pla 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). -### `(0 , _c) is not a function` error {/*0--_c-is-not-a-function-error*/} - -This occurs if you are not using React 19 RC and up. To fix this, [upgrade your app to React 19 RC](https://react.dev/blog/2024/04/25/react-19-upgrade-guide) first. - -If you are unable to upgrade to React 19, you may try a userspace implementation of the cache function as described in the [Working Group](https://github.com/reactwg/react-compiler/discussions/6). However, please note that this is not recommended and you should upgrade to React 19 when possible. - ### 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+) has built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler. From 9467bc58868e66c53ca9385c8531dcf7b02178c2 Mon Sep 17 00:00:00 2001 From: lauren Date: Fri, 18 Oct 2024 00:12:01 -0400 Subject: [PATCH 3/3] [compiler] Add docs for Beta (#7231) Updates our compiler docs for the latest Beta release. --- src/content/learn/react-compiler.md | 146 +++++++++------------------- 1 file changed, 48 insertions(+), 98 deletions(-) diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md index 08e2e5672..4fc974fa9 100644 --- a/src/content/learn/react-compiler.md +++ b/src/content/learn/react-compiler.md @@ -3,7 +3,7 @@ title: React Compiler --- -This page will give you an introduction to the new experimental React Compiler and how to try it out successfully. +This page will give you an introduction to React Compiler and how to try it out successfully. @@ -19,12 +19,28 @@ These docs are still a work in progress. More documentation is available in the -React Compiler is a new experimental compiler that we've open sourced to get early feedback from the community. It still has rough edges and is not yet fully ready for production. +React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. 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). + +The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`. -React Compiler is a new experimental compiler that we've open sourced to get early 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. +React Compiler is a new compiler that we've open sourced to get early 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. + +The compiler also includes an [eslint plugin](#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 `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta: -The compiler also includes an [eslint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. The plugin runs independently of the compiler and can be used even if you aren't using the compiler in your app. We recommend all React developers to use this eslint plugin to help improve the quality of your codebase. + +npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta + + +Or, if you're using Yarn: + + +yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta + + +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*/} @@ -94,19 +110,9 @@ However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive 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. -### 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). - ### Should I try out the compiler? {/*should-i-try-out-the-compiler*/} -Please note that the compiler is still experimental and has many rough edges. 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). +Please note that the compiler is still in Beta and has many rough edges. 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. @@ -119,7 +125,7 @@ In addition to these docs, we recommend checking the [React Compiler Working Gro Prior to installing the compiler, you can first check to see if your codebase is compatible: -npx react-compiler-healthcheck@experimental +npx react-compiler-healthcheck@beta This script will: @@ -141,7 +147,7 @@ Found no usage of incompatible libraries. React Compiler also powers an eslint plugin. The eslint plugin can be used **independently** of the compiler, meaning you can use the eslint plugin even if you don't use the compiler. -npm install eslint-plugin-react-compiler@experimental +npm install -D eslint-plugin-react-compiler@beta Then, add it to your eslint config: @@ -176,28 +182,18 @@ const ReactCompilerConfig = { }; ``` -In rare cases, you can also configure the compiler to run in "opt-in" mode using the `compilationMode: "annotation"` option. This makes it so the compiler will only compile components and hooks annotated with a `"use memo"` directive. Please note that the `annotation` mode is a temporary one to aid early adopters, and that we don't intend for the `"use memo"` directive to be used for the long term. - -```js {2,7} -const ReactCompilerConfig = { - compilationMode: "annotation", -}; +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. -// src/app.jsx -export default function App() { - "use memo"; - // ... -} -``` +#### New projects {/*new-projects*/} -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. +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@experimental +npm install react-compiler-runtime@beta You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting: @@ -217,16 +213,22 @@ module.exports = function () { }; ``` -#### New projects {/*new-projects*/} +### Using the compiler on libraries {/*using-the-compiler-on-libraries*/} -If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior. +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@experimental +npm install babel-plugin-react-compiler@beta The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler. @@ -275,36 +277,7 @@ export default defineConfig(() => { ### Next.js {/*usage-with-nextjs*/} -Next.js has an experimental configuration to enable the React Compiler. It automatically ensures Babel is set up with `babel-plugin-react-compiler`. - -- Install Next.js canary, which uses React 19 Release Candidate -- Install `babel-plugin-react-compiler` - - -npm install next@canary babel-plugin-react-compiler@experimental - - -Then configure the experimental option in `next.config.js`: - -```js {4,5,6} -// next.config.js -/** @type {import('next').NextConfig} */ -const nextConfig = { - experimental: { - reactCompiler: true, - }, -}; - -module.exports = nextConfig; -``` - -Using the experimental option ensures support for the React Compiler in: - -- App Router -- Pages Router -- Webpack (default) -- Turbopack (opt-in through `--turbo`) - +Please refer to the [Next.js docs](https://nextjs.org/docs/canary/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: @@ -337,40 +310,7 @@ export default defineConfig({ ### Webpack {/*usage-with-webpack*/} -You can create your own loader for React Compiler, like so: - -```js -const ReactCompilerConfig = { /* ... */ }; -const BabelPluginReactCompiler = require('babel-plugin-react-compiler'); - -function reactCompilerLoader(sourceCode, sourceMap) { - // ... - const result = transformSync(sourceCode, { - // ... - plugins: [ - [BabelPluginReactCompiler, ReactCompilerConfig], - ], - // ... - }); - - if (result === null) { - this.callback( - Error( - `Failed to transform "${options.filename}"` - ) - ); - return; - } - - this.callback( - null, - result.code, - result.map === null ? undefined : result.map - ); -} - -module.exports = reactCompilerLoader; -``` +A community Webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack). ### Expo {/*usage-with-expo*/} @@ -394,6 +334,16 @@ To report issues, please first create a minimal repro on the [React Compiler Pla 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+) has built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler.