diff --git a/src/content/learn/describing-the-ui.md b/src/content/learn/describing-the-ui.md index 339f04223cf..34ee0c01a1d 100644 --- a/src/content/learn/describing-the-ui.md +++ b/src/content/learn/describing-the-ui.md @@ -474,7 +474,7 @@ By strictly only writing your components as pure functions, you can avoid an ent -```js {expectedErrors: {'react-compiler': [5]}} +```js let guest = 0; function Cup() { diff --git a/src/content/learn/escape-hatches.md b/src/content/learn/escape-hatches.md index 0b2d595b2bd..23f11f54e28 100644 --- a/src/content/learn/escape-hatches.md +++ b/src/content/learn/escape-hatches.md @@ -201,7 +201,7 @@ There are two common cases in which you don't need Effects: For example, you don't need an Effect to adjust some state based on other state: -```js {expectedErrors: {'react-compiler': [8]}} {5-9} +```js {5-9} function Form() { const [firstName, setFirstName] = useState('Taylor'); const [lastName, setLastName] = useState('Swift'); diff --git a/src/content/learn/keeping-components-pure.md b/src/content/learn/keeping-components-pure.md index fafd488e33b..70049e58e27 100644 --- a/src/content/learn/keeping-components-pure.md +++ b/src/content/learn/keeping-components-pure.md @@ -93,7 +93,7 @@ Here is a component that breaks this rule: -```js {expectedErrors: {'react-compiler': [5]}} +```js let guest = 0; function Cup() { @@ -380,7 +380,7 @@ The buggy code is in `Profile.js`. Make sure you read it all from top to bottom! -```js {expectedErrors: {'react-compiler': [7]}} src/Profile.js +```js src/Profile.js import Panel from './Panel.js'; import { getImageUrl } from './utils.js'; @@ -602,7 +602,7 @@ export default function StoryTray({ stories }) { } ``` -```js {expectedErrors: {'react-compiler': [16]}} src/App.js hidden +```js src/App.js hidden import { useState, useEffect } from 'react'; import StoryTray from './StoryTray.js'; @@ -698,7 +698,7 @@ export default function StoryTray({ stories }) { } ``` -```js {expectedErrors: {'react-compiler': [16]}} src/App.js hidden +```js src/App.js hidden import { useState, useEffect } from 'react'; import StoryTray from './StoryTray.js'; @@ -790,7 +790,7 @@ export default function StoryTray({ stories }) { } ``` -```js {expectedErrors: {'react-compiler': [16]}} src/App.js hidden +```js src/App.js hidden import { useState, useEffect } from 'react'; import StoryTray from './StoryTray.js'; diff --git a/src/content/learn/lifecycle-of-reactive-effects.md b/src/content/learn/lifecycle-of-reactive-effects.md index 72a2e77559f..3dc9a75f02b 100644 --- a/src/content/learn/lifecycle-of-reactive-effects.md +++ b/src/content/learn/lifecycle-of-reactive-effects.md @@ -1131,7 +1131,7 @@ If you see a linter rule being suppressed, remove the suppression! That's where -```js {expectedErrors: {'react-compiler': [16]}} +```js import { useState, useEffect } from 'react'; export default function App() { @@ -1374,7 +1374,7 @@ export default function App() { } ``` -```js {expectedErrors: {'react-compiler': [8]}} src/ChatRoom.js active +```js src/ChatRoom.js active import { useState, useEffect } from 'react'; export default function ChatRoom({ roomId, createConnection }) { diff --git a/src/content/learn/preserving-and-resetting-state.md b/src/content/learn/preserving-and-resetting-state.md index 041fae35508..11d398d23f9 100644 --- a/src/content/learn/preserving-and-resetting-state.md +++ b/src/content/learn/preserving-and-resetting-state.md @@ -704,7 +704,7 @@ Here, the `MyTextField` component function is defined *inside* `MyComponent`: -```js {expectedErrors: {'react-compiler': [7]}} +```js import { useState } from 'react'; export default function MyComponent() { diff --git a/src/content/learn/react-compiler/introduction.md b/src/content/learn/react-compiler/introduction.md index 96fa8802a0e..9957b8227e1 100644 --- a/src/content/learn/react-compiler/introduction.md +++ b/src/content/learn/react-compiler/introduction.md @@ -28,7 +28,7 @@ React Compiler automatically optimizes your React application at build time. Rea Without the compiler, you need to manually memoize components and values to optimize re-renders: -```js {expectedErrors: {'react-compiler': [4]}} +```js import { useMemo, useCallback, memo } from 'react'; const ExpensiveComponent = memo(function ExpensiveComponent({ data, onClick }) { diff --git a/src/content/learn/referencing-values-with-refs.md b/src/content/learn/referencing-values-with-refs.md index 4386e2bdc44..fab6599f26d 100644 --- a/src/content/learn/referencing-values-with-refs.md +++ b/src/content/learn/referencing-values-with-refs.md @@ -211,7 +211,7 @@ If you tried to implement this with a ref, React would never re-render the compo -```js {expectedErrors: {'react-compiler': [13]}} +```js import { useRef } from 'react'; export default function Counter() { @@ -313,7 +313,7 @@ Regular variables like `let timeoutID` don't "survive" between re-renders becaus -```js {expectedErrors: {'react-compiler': [10]}} +```js import { useState } from 'react'; export default function Chat() { @@ -418,7 +418,7 @@ This button is supposed to toggle between showing "On" and "Off". However, it al -```js {expectedErrors: {'react-compiler': [10]}} +```js import { useRef } from 'react'; export default function Toggle() { diff --git a/src/content/learn/removing-effect-dependencies.md b/src/content/learn/removing-effect-dependencies.md index 7ab6dbc1f42..9a848862a36 100644 --- a/src/content/learn/removing-effect-dependencies.md +++ b/src/content/learn/removing-effect-dependencies.md @@ -303,7 +303,7 @@ Suppressing the linter leads to very unintuitive bugs that are hard to find and -```js {expectedErrors: {'react-compiler': [14]}} +```js import { useState, useEffect } from 'react'; export default function Timer() { @@ -794,7 +794,7 @@ It is important to declare it as a dependency! This ensures, for example, that i -```js {expectedErrors: {'react-compiler': [10]}} +```js import { useState, useEffect } from 'react'; import { createConnection } from './chat.js'; diff --git a/src/content/learn/responding-to-events.md b/src/content/learn/responding-to-events.md index 78474217c40..17bd087ed25 100644 --- a/src/content/learn/responding-to-events.md +++ b/src/content/learn/responding-to-events.md @@ -546,7 +546,7 @@ Clicking this button is supposed to switch the page background between white and -```js {expectedErrors: {'react-compiler': [5, 7]}} +```js export default function LightSwitch() { function handleClick() { let bodyStyle = document.body.style; diff --git a/src/content/learn/separating-events-from-effects.md b/src/content/learn/separating-events-from-effects.md index fd603c39556..03223183b13 100644 --- a/src/content/learn/separating-events-from-effects.md +++ b/src/content/learn/separating-events-from-effects.md @@ -711,7 +711,7 @@ Here, `url` inside `onVisit` corresponds to the *latest* `url` (which could have In the existing codebases, you may sometimes see the lint rule suppressed like this: -```js {expectedErrors: {'react-compiler': [8]}} {7-9} +```js {7-9} function Page({ url }) { const { items } = useContext(ShoppingCartContext); const numberOfItems = items.length; @@ -735,7 +735,7 @@ Can you see why? -```js {expectedErrors: {'react-compiler': [16]}} +```js import { useState, useEffect } from 'react'; export default function App() { @@ -990,7 +990,7 @@ To fix this code, it's enough to follow the rules. ``` -```js {expectedErrors: {'react-compiler': [14]}} +```js import { useState, useEffect } from 'react'; export default function Timer() { diff --git a/src/content/learn/state-a-components-memory.md b/src/content/learn/state-a-components-memory.md index 0efe1191db0..73d46bdab86 100644 --- a/src/content/learn/state-a-components-memory.md +++ b/src/content/learn/state-a-components-memory.md @@ -23,7 +23,7 @@ Here's a component that renders a sculpture image. Clicking the "Next" button sh -```js {expectedErrors: {'react-compiler': [7]}} +```js import { sculptureList } from './data.js'; export default function Gallery() { @@ -1229,7 +1229,7 @@ When you type into the input fields, nothing appears. It's like the input values -```js {expectedErrors: {'react-compiler': [6]}} +```js export default function Form() { let firstName = ''; let lastName = ''; @@ -1337,7 +1337,7 @@ Are there any limitations on _where_ Hooks may be called? Does this component br -```js {expectedErrors: {'react-compiler': [9]}} +```js import { useState } from 'react'; export default function FeedbackForm() { diff --git a/src/content/learn/synchronizing-with-effects.md b/src/content/learn/synchronizing-with-effects.md index 7f61a255bb4..c0ad34709b9 100644 --- a/src/content/learn/synchronizing-with-effects.md +++ b/src/content/learn/synchronizing-with-effects.md @@ -95,7 +95,7 @@ You might be tempted to try to call `play()` or `pause()` during rendering, but -```js {expectedErrors: {'react-compiler': [7, 9]}} +```js import { useState, useRef, useEffect } from 'react'; function VideoPlayer({ src, isPlaying }) { @@ -617,7 +617,7 @@ A common pitfall for preventing Effects firing twice in development is to use a This makes it so you only see `"✅ Connecting..."` once in development, but it doesn't fix the bug. -When the user navigates away, the connection still isn't closed and when they navigate back, a new connection is created. As the user navigates across the app, the connections would keep piling up, the same as it would before the "fix". +When the user navigates away, the connection still isn't closed and when they navigate back, a new connection is created. As the user navigates across the app, the connections would keep piling up, the same as it would before the "fix". To fix the bug, it is not enough to just make the Effect run once. The effect needs to work after re-mounting, which means the connection needs to be cleaned up like in the solution above. @@ -1005,7 +1005,7 @@ export default function MyInput({ value, onChange }) { const ref = useRef(null); // TODO: This doesn't quite work. Fix it. - // ref.current.focus() + // ref.current.focus() return ( -{/* not the most efficient, but this validation is enabled in the linter only, so it's fine to ignore it here since we know what we're doing */} -```js {expectedErrors: {'react-compiler': [9]}} src/App.js +```js src/App.js import { useState, useEffect } from 'react'; import { fetchBio } from './api.js'; @@ -1542,8 +1541,7 @@ To fix this race condition, add a cleanup function: -{/* not the most efficient, but this validation is enabled in the linter only, so it's fine to ignore it here since we know what we're doing */} -```js {expectedErrors: {'react-compiler': [9]}} src/App.js +```js src/App.js import { useState, useEffect } from 'react'; import { fetchBio } from './api.js'; @@ -1607,3 +1605,4 @@ In addition to ignoring the result of an outdated API call, you can also use [`A + diff --git a/src/content/learn/updating-objects-in-state.md b/src/content/learn/updating-objects-in-state.md index ca658514507..93ea93bd2d9 100644 --- a/src/content/learn/updating-objects-in-state.md +++ b/src/content/learn/updating-objects-in-state.md @@ -55,7 +55,7 @@ This example holds an object in state to represent the current pointer position. -```js {expectedErrors: {'react-compiler': [11]}} +```js import { useState } from 'react'; export default function MovingDot() { @@ -209,7 +209,7 @@ These input fields don't work because the `onChange` handlers mutate the state: -```js {expectedErrors: {'react-compiler': [11, 15, 19]}} +```js import { useState } from 'react'; export default function Form() { @@ -832,7 +832,7 @@ Your task is to fix all of these bugs. As you fix them, explain why each of them -```js {expectedErrors: {'react-compiler': [11]}} +```js import { useState } from 'react'; export default function Scoreboard() { @@ -988,7 +988,7 @@ If something unexpected changes, there is a mutation. Find the mutation in `App. -```js {expectedErrors: {'react-compiler': [17]}} src/App.js +```js src/App.js import { useState } from 'react'; import Background from './Background.js'; import Box from './Box.js'; @@ -1293,7 +1293,7 @@ This is the same buggy example as in the previous challenge. This time, fix the -```js {expectedErrors: {'react-compiler': [18]}} src/App.js +```js src/App.js import { useState } from 'react'; import { useImmer } from 'use-immer'; import Background from './Background.js'; 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 39a1dc74045..88e490e1aea 100644 --- a/src/content/learn/you-might-not-need-an-effect.md +++ b/src/content/learn/you-might-not-need-an-effect.md @@ -34,7 +34,7 @@ To help you gain the right intuition, let's look at some common concrete example Suppose you have a component with two state variables: `firstName` and `lastName`. You want to calculate a `fullName` from them by concatenating them. Moreover, you'd like `fullName` to update whenever `firstName` or `lastName` change. Your first instinct might be to add a `fullName` state variable and update it in an Effect: -```js {expectedErrors: {'react-compiler': [8]}} {5-9} +```js {5-9} function Form() { const [firstName, setFirstName] = useState('Taylor'); const [lastName, setLastName] = useState('Swift'); @@ -66,7 +66,7 @@ function Form() { This component computes `visibleTodos` by taking the `todos` it receives by props and filtering them according to the `filter` prop. You might feel tempted to store the result in state and update it from an Effect: -```js {expectedErrors: {'react-compiler': [7]}} {4-8} +```js {4-8} function TodoList({ todos, filter }) { const [newTodo, setNewTodo] = useState(''); @@ -165,7 +165,7 @@ Also note that measuring performance in development will not give you the most a This `ProfilePage` component receives a `userId` prop. The page contains a comment input, and you use a `comment` state variable to hold its value. One day, you notice a problem: when you navigate from one profile to another, the `comment` state does not get reset. As a result, it's easy to accidentally post a comment on a wrong user's profile. To fix the issue, you want to clear out the `comment` state variable whenever the `userId` changes: -```js {expectedErrors: {'react-compiler': [6]}} {4-7} +```js {4-7} export default function ProfilePage({ userId }) { const [comment, setComment] = useState(''); @@ -208,7 +208,7 @@ Sometimes, you might want to reset or adjust a part of the state on a prop chang This `List` component receives a list of `items` as a prop, and maintains the selected item in the `selection` state variable. You want to reset the `selection` to `null` whenever the `items` prop receives a different array: -```js {expectedErrors: {'react-compiler': [7]}} {5-8} +```js {5-8} function List({ items }) { const [isReverse, setIsReverse] = useState(false); const [selection, setSelection] = useState(null); @@ -819,7 +819,7 @@ Simplify this component by removing all the unnecessary state and Effects. -```js {expectedErrors: {'react-compiler': [12, 16, 20]}} +```js import { useState, useEffect } from 'react'; import { initialTodos, createTodo } from './todos.js'; @@ -1022,7 +1022,7 @@ One solution is to add a `useMemo` call to cache the visible todos. There is als -```js {expectedErrors: {'react-compiler': [11]}} +```js import { useState, useEffect } from 'react'; import { initialTodos, createTodo, getVisibleTodos } from './todos.js'; @@ -1106,7 +1106,7 @@ Remove the state variable and the Effect, and instead add a `useMemo` call to ca -```js {expectedErrors: {'react-compiler': [8]}} +```js import { useState, useMemo } from 'react'; import { initialTodos, createTodo, getVisibleTodos } from './todos.js'; @@ -1363,7 +1363,7 @@ export default function ContactList({ } ``` -```js {expectedErrors: {'react-compiler': [8, 9]}} src/EditContact.js active +```js src/EditContact.js active import { useState, useEffect } from 'react'; export default function EditContact({ savedContact, onSave }) { diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md index c48b6eb5196..b74e2c38ee3 100644 --- a/src/content/reference/react-dom/client/hydrateRoot.md +++ b/src/content/reference/react-dom/client/hydrateRoot.md @@ -296,8 +296,7 @@ import App from './App.js'; hydrateRoot(document.getElementById('root'), ); ``` -{/* kind of an edge case, seems fine to use this hack here */} -```js {expectedErrors: {'react-compiler': [7]}} src/App.js active +```js src/App.js active import { useState, useEffect } from "react"; export default function App() { diff --git a/src/content/reference/react-dom/createPortal.md b/src/content/reference/react-dom/createPortal.md index 4521dfa479b..e806660e869 100644 --- a/src/content/reference/react-dom/createPortal.md +++ b/src/content/reference/react-dom/createPortal.md @@ -398,8 +398,7 @@ Here is a complete example you can play with: } ``` -{/* TODO(@poteto) - fixed by https://github.com/facebook/react/pull/34462. need a new release */} -```js {expectedErrors: {'react-compiler': [15]}} src/App.js +```js src/App.js import { useRef, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import { createMapWidget, addPopupToMapWidget } from './map-widget.js'; diff --git a/src/content/reference/react/cache.md b/src/content/reference/react/cache.md index c82543479c6..4425848082f 100644 --- a/src/content/reference/react/cache.md +++ b/src/content/reference/react/cache.md @@ -65,7 +65,7 @@ The optimization of caching return values based on inputs is known as [_memoizat [//]: # 'TODO: add links to Server/Client Component reference once https://github.com/reactjs/react.dev/pull/6177 is merged' -- React will invalidate the cache for all memoized functions for each server request. +- React will invalidate the cache for all memoized functions for each server request. - Each call to `cache` creates a new function. This means that calling `cache` with the same function multiple times will return different memoized functions that do not share the same cache. - `cachedFn` will also cache errors. If `fn` throws an error for certain arguments, it will be cached, and the same error is re-thrown when `cachedFn` is called with those same arguments. - `cache` is for use in [Server Components](/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023#react-server-components) only. @@ -98,9 +98,9 @@ function TeamReport({users}) { } ``` -If the same `user` object is rendered in both `Profile` and `TeamReport`, the two components can share work and only call `calculateUserMetrics` once for that `user`. +If the same `user` object is rendered in both `Profile` and `TeamReport`, the two components can share work and only call `calculateUserMetrics` once for that `user`. -Assume `Profile` is rendered first. It will call `getUserMetrics`, and check if there is a cached result. Since it is the first time `getUserMetrics` is called with that `user`, there will be a cache miss. `getUserMetrics` will then call `calculateUserMetrics` with that `user` and write the result to cache. +Assume `Profile` is rendered first. It will call `getUserMetrics`, and check if there is a cached result. Since it is the first time `getUserMetrics` is called with that `user`, there will be a cache miss. `getUserMetrics` will then call `calculateUserMetrics` with that `user` and write the result to cache. When `TeamReport` renders its list of `users` and reaches the same `user` object, it will call `getUserMetrics` and read the result from cache. @@ -170,12 +170,12 @@ export default function Precipitation({cityData}) { // ... } ``` -Here, both components call the same memoized function exported from `./getWeekReport.js` to read and write to the same cache. +Here, both components call the same memoized function exported from `./getWeekReport.js` to read and write to the same cache. ### Share a snapshot of data {/*take-and-share-snapshot-of-data*/} -To share a snapshot of data between components, call `cache` with a data-fetching function like `fetch`. When multiple components make the same data fetch, only one request is made and the data returned is cached and shared across components. All components refer to the same snapshot of data across the server render. +To share a snapshot of data between components, call `cache` with a data-fetching function like `fetch`. When multiple components make the same data fetch, only one request is made and the data returned is cached and shared across components. All components refer to the same snapshot of data across the server render. ```js [[1, 4, "city"], [1, 5, "fetchTemperature(city)"], [2, 4, "getTemperature"], [2, 9, "getTemperature"], [1, 9, "city"], [2, 14, "getTemperature"], [1, 14, "city"]] import {cache} from 'react'; @@ -196,7 +196,7 @@ async function MinimalWeatherCard({city}) { } ``` -If `AnimatedWeatherCard` and `MinimalWeatherCard` both render for the same city, they will receive the same snapshot of data from the memoized function. +If `AnimatedWeatherCard` and `MinimalWeatherCard` both render for the same city, they will receive the same snapshot of data from the memoized function. If `AnimatedWeatherCard` and `MinimalWeatherCard` supply different city arguments to `getTemperature`, then `fetchTemperature` will be called twice and each call site will receive different data. @@ -260,7 +260,7 @@ When rendering `Profile`, we call `getUser` again. When evaluating an [asynchronous function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function), you will receive a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) for that work. The promise holds the state of that work (_pending_, _fulfilled_, _failed_) and its eventual settled result. -In this example, the asynchronous function `fetchData` returns a promise that is awaiting the `fetch`. +In this example, the asynchronous function `fetchData` returns a promise that is awaiting the `fetch`. ```js [[1, 1, "fetchData()"], [2, 8, "getData()"], [3, 10, "getData()"]] async function fetchData() { @@ -271,7 +271,7 @@ const getData = cache(fetchData); async function MyComponent() { getData(); - // ... some computational work + // ... some computational work await getData(); // ... } @@ -281,7 +281,7 @@ In calling `getData` the first time, the promise r Notice that the first `getData` call does not `await` whereas the second does. [`await`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await) is a JavaScript operator that will wait and return the settled result of the promise. The first `getData` call simply initiates the `fetch` to cache the promise for the second `getData` to look-up. -If by the second call the promise is still _pending_, then `await` will pause for the result. The optimization is that while we wait on the `fetch`, React can continue with computational work, thus reducing the wait time for the second call. +If by the second call the promise is still _pending_, then `await` will pause for the result. The optimization is that while we wait on the `fetch`, React can continue with computational work, thus reducing the wait time for the second call. If the promise is already settled, either to an error or the _fulfilled_ result, `await` will return that value immediately. In both outcomes, there is a performance benefit. @@ -309,7 +309,7 @@ async function DemoProfile() { React only provides cache access to the memoized function in a component. When calling `getUser` outside of a component, it will still evaluate the function but not read or update the cache. -This is because cache access is provided through a [context](/learn/passing-data-deeply-with-context) which is only accessible from a component. +This is because cache access is provided through a [context](/learn/passing-data-deeply-with-context) which is only accessible from a component. @@ -323,7 +323,7 @@ All mentioned APIs offer memoization but the difference is what they're intended In general, you should use [`useMemo`](/reference/react/useMemo) for caching an expensive computation in a Client Component across renders. As an example, to memoize a transformation of data within a component. -```jsx {expectedErrors: {'react-compiler': [4]}} {4} +```jsx {4} 'use client'; function WeatherReport({record}) { @@ -343,7 +343,7 @@ function App() { ``` In this example, `App` renders two `WeatherReport`s with the same record. Even though both components do the same work, they cannot share work. `useMemo`'s cache is only local to the component. -However, `useMemo` does ensure that if `App` re-renders and the `record` object doesn't change, each component instance would skip work and use the memoized value of `avgTemp`. `useMemo` will only cache the last computation of `avgTemp` with the given dependencies. +However, `useMemo` does ensure that if `App` re-renders and the `record` object doesn't change, each component instance would skip work and use the memoized value of `avgTemp`. `useMemo` will only cache the last computation of `avgTemp` with the given dependencies. #### `cache` {/*deep-dive-cache*/} @@ -379,7 +379,7 @@ You should use [`memo`](reference/react/memo) to prevent a component re-renderin 'use client'; function WeatherReport({record}) { - const avgTemp = calculateAvg(record); + const avgTemp = calculateAvg(record); // ... } @@ -396,7 +396,7 @@ function App() { } ``` -In this example, both `MemoWeatherReport` components will call `calculateAvg` when first rendered. However, if `App` re-renders, with no changes to `record`, none of the props have changed and `MemoWeatherReport` will not re-render. +In this example, both `MemoWeatherReport` components will call `calculateAvg` when first rendered. However, if `App` re-renders, with no changes to `record`, none of the props have changed and `MemoWeatherReport` will not re-render. Compared to `useMemo`, `memo` memoizes the component render based on props vs. specific computations. Similar to `useMemo`, the memoized component only caches the last render with the last prop values. Once the props change, the cache invalidates and the component re-renders. @@ -495,3 +495,4 @@ function App() { ); } ``` + diff --git a/src/content/reference/react/useCallback.md b/src/content/reference/react/useCallback.md index 9a1520f44d9..acae804eccb 100644 --- a/src/content/reference/react/useCallback.md +++ b/src/content/reference/react/useCallback.md @@ -130,7 +130,7 @@ function ProductPage({ productId, referrer, theme }) { orderDetails, }); } - + return (
{/* ... so ShippingForm's props will never be the same, and it will re-render every time */} @@ -207,7 +207,7 @@ The difference is in *what* they're letting you cache: If you're already familiar with [`useMemo`,](/reference/react/useMemo) you might find it helpful to think of `useCallback` as this: -```js {expectedErrors: {'react-compiler': [3]}} +```js // Simplified implementation (inside React) function useCallback(fn, dependencies) { return useMemo(() => fn, dependencies); @@ -222,7 +222,7 @@ function useCallback(fn, dependencies) { #### Should you add useCallback everywhere? {/*should-you-add-usecallback-everywhere*/} -If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful. +If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful. Caching a function with `useCallback` is only valuable in a few cases: @@ -310,7 +310,7 @@ function post(url, data) { } ``` -```js {expectedErrors: {'react-compiler': [7, 8]}} src/ShippingForm.js +```js src/ShippingForm.js import { memo, useState } from 'react'; const ShippingForm = memo(function ShippingForm({ onSubmit }) { @@ -449,7 +449,7 @@ function post(url, data) { } ``` -```js {expectedErrors: {'react-compiler': [7, 8]}} src/ShippingForm.js +```js src/ShippingForm.js import { memo, useState } from 'react'; const ShippingForm = memo(function ShippingForm({ onSubmit }) { @@ -868,7 +868,7 @@ When you find which dependency is breaking memoization, either find a way to rem Suppose the `Chart` component is wrapped in [`memo`](/reference/react/memo). You want to skip re-rendering every `Chart` in the list when the `ReportList` component re-renders. However, you can't call `useCallback` in a loop: -```js {expectedErrors: {'react-compiler': [6]}} {5-14} +```js {5-14} function ReportList({ items }) { return (
diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index bf716b17338..ed561c977b7 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -244,7 +244,7 @@ input { margin: 10px; } -A common alternative UI pattern is to *defer* updating the list of results and to keep showing the previous results until the new results are ready. Call `useDeferredValue` to pass a deferred version of the query down: +A common alternative UI pattern is to *defer* updating the list of results and to keep showing the previous results until the new results are ready. Call `useDeferredValue` to pass a deferred version of the query down: ```js {3,11} export default function App() { @@ -669,7 +669,7 @@ export default function App() { } ``` -```js {expectedErrors: {'react-compiler': [19, 20]}} src/SlowList.js +```js src/SlowList.js import { memo } from 'react'; const SlowList = memo(function SlowList({ text }) { @@ -746,7 +746,7 @@ export default function App() { } ``` -```js {expectedErrors: {'react-compiler': [19, 20]}} src/SlowList.js +```js src/SlowList.js import { memo } from 'react'; const SlowList = memo(function SlowList({ text }) { diff --git a/src/content/reference/react/useEffect.md b/src/content/reference/react/useEffect.md index a250bb15a24..e93e6110259 100644 --- a/src/content/reference/react/useEffect.md +++ b/src/content/reference/react/useEffect.md @@ -928,8 +928,7 @@ Note the `ignore` variable which is initialized to `false`, and is set to `true` -{/* TODO(@poteto) - investigate potential false positives in react compiler validation */} -```js {expectedErrors: {'react-compiler': [9]}} src/App.js +```js src/App.js import { useState, useEffect } from 'react'; import { fetchBio } from './api.js'; @@ -1738,9 +1737,7 @@ If your app uses server rendering (either [directly](/reference/react-dom/server In rare cases, you might need to display different content on the client. For example, if your app reads some data from [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage), it can't possibly do that on the server. Here is how you could implement this: - -{/* TODO(@poteto) - investigate potential false positives in react compiler validation */} -```js {expectedErrors: {'react-compiler': [5]}} +```js function MyComponent() { const [didMount, setDidMount] = useState(false); diff --git a/src/content/reference/react/useLayoutEffect.md b/src/content/reference/react/useLayoutEffect.md index e562e623ae1..d38458f146e 100644 --- a/src/content/reference/react/useLayoutEffect.md +++ b/src/content/reference/react/useLayoutEffect.md @@ -48,7 +48,7 @@ function Tooltip() { #### Parameters {/*parameters*/} * `setup`: The function with your Effect's logic. Your setup function may also optionally return a *cleanup* function. Before your component is added to the DOM, React will run your setup function. After every re-render with changed dependencies, React will first run the cleanup function (if you provided it) with the old values, and then run your setup function with the new values. Before your component is removed from the DOM, React will run your cleanup function. - + * **optional** `dependencies`: The list of all reactive values referenced inside of the `setup` code. Reactive values include props, state, and all the variables and functions declared directly inside your component body. If your linter is [configured for React](/learn/editor-setup#linting), it will verify that every reactive value is correctly specified as a dependency. The list of dependencies must have a constant number of items and be written inline like `[dep1, dep2, dep3]`. React will compare each dependency with its previous value using the [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is) comparison. If you omit this argument, your Effect will re-run after every re-render of the component. #### Returns {/*returns*/} @@ -87,8 +87,7 @@ To do this, you need to render in two passes: **All of this needs to happen before the browser repaints the screen.** You don't want the user to see the tooltip moving. Call `useLayoutEffect` to perform the layout measurements before the browser repaints the screen: -{/* TODO(@poteto) - fixed by https://github.com/facebook/react/pull/34462. need a new release */} -```js {expectedErrors: {'react-compiler': [7]}} {5-8} +```js {5-8} function Tooltip() { const ref = useRef(null); const [tooltipHeight, setTooltipHeight] = useState(0); // You don't know real height yet @@ -188,8 +187,7 @@ export default function ButtonWithTooltip({ tooltipContent, ...rest }) { } ``` -{/* TODO(@poteto) - fixed by https://github.com/facebook/react/pull/34462. need a new release */} -```js {expectedErrors: {'react-compiler': [11]}} src/Tooltip.js active +```js src/Tooltip.js active import { useRef, useLayoutEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import TooltipContainer from './TooltipContainer.js'; @@ -339,8 +337,7 @@ export default function ButtonWithTooltip({ tooltipContent, ...rest }) { } ``` -{/* TODO(@poteto) - fixed by https://github.com/facebook/react/pull/34462. need a new release */} -```js {expectedErrors: {'react-compiler': [11]}} src/Tooltip.js active +```js src/Tooltip.js active import { useRef, useLayoutEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import TooltipContainer from './TooltipContainer.js'; @@ -487,8 +484,7 @@ export default function ButtonWithTooltip({ tooltipContent, ...rest }) { } ``` -{/* TODO(@poteto) - fixed by https://github.com/facebook/react/pull/34462. need a new release */} -```js {expectedErrors: {'react-compiler': [11]}} src/Tooltip.js active +```js src/Tooltip.js active import { useRef, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import TooltipContainer from './TooltipContainer.js'; @@ -631,7 +627,7 @@ export default function ButtonWithTooltip({ tooltipContent, ...rest }) { } ``` -```js {expectedErrors: {'react-compiler': [10, 11]}} src/Tooltip.js active +```js src/Tooltip.js active import { useRef, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import TooltipContainer from './TooltipContainer.js'; diff --git a/src/content/reference/react/useMemo.md b/src/content/reference/react/useMemo.md index bbb2ad622dd..f0bdd77fb12 100644 --- a/src/content/reference/react/useMemo.md +++ b/src/content/reference/react/useMemo.md @@ -149,7 +149,7 @@ Also note that measuring performance in development will not give you the most a #### Should you add useMemo everywhere? {/*should-you-add-usememo-everywhere*/} -If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful. +If your app is like this site, and most interactions are coarse (like replacing a page or an entire section), memoization is usually unnecessary. On the other hand, if your app is more like a drawing editor, and most interactions are granular (like moving shapes), then you might find memoization very helpful. Optimizing with `useMemo` is only valuable in a few cases: @@ -225,8 +225,7 @@ export default function App() { ``` -{/* TODO(@poteto) - investigate potential false positives in react compiler validation */} -```js {expectedErrors: {'react-compiler': [5]}} src/TodoList.js active +```js src/TodoList.js active import { useMemo } from 'react'; import { filterTodos } from './utils.js' @@ -718,7 +717,7 @@ export default function TodoList({ todos, theme, tab }) { } ``` -```js {expectedErrors: {'react-compiler': [5, 6]}} src/List.js +```js src/List.js import { memo } from 'react'; const List = memo(function List({ items }) { @@ -856,7 +855,7 @@ export default function TodoList({ todos, theme, tab }) { } ``` -```js {expectedErrors: {'react-compiler': [5, 6]}} src/List.js +```js src/List.js import { memo } from 'react'; const List = memo(function List({ items }) { @@ -1128,7 +1127,7 @@ function ChatRoom({ roomId }) { serverUrl: 'https://localhost:1234', roomId: roomId } - + const connection = createConnection(options); connection.connect(); return () => connection.disconnect(); @@ -1372,7 +1371,7 @@ When you find which dependency breaks memoization, either find a way to remove i Suppose the `Chart` component is wrapped in [`memo`](/reference/react/memo). You want to skip re-rendering every `Chart` in the list when the `ReportList` component re-renders. However, you can't call `useMemo` in a loop: -```js {expectedErrors: {'react-compiler': [6]}} {5-11} +```js {5-11} function ReportList({ items }) { return (
diff --git a/src/content/reference/react/useRef.md b/src/content/reference/react/useRef.md index e87ef6b8a24..8ab53aef371 100644 --- a/src/content/reference/react/useRef.md +++ b/src/content/reference/react/useRef.md @@ -197,7 +197,7 @@ React expects that the body of your component [behaves like a pure function](/le Reading or writing a ref **during rendering** breaks these expectations. -```js {expectedErrors: {'react-compiler': [4]}} {3-4,6-7} +```js {3-4,6-7} function MyComponent() { // ... // 🚩 Don't write a ref during rendering diff --git a/src/content/reference/react/useTransition.md b/src/content/reference/react/useTransition.md index 923b6c0c9a7..52707814334 100644 --- a/src/content/reference/react/useTransition.md +++ b/src/content/reference/react/useTransition.md @@ -161,7 +161,7 @@ function CheckoutForm() { } ``` -The function passed to `startTransition` is called the "Action". You can update state and (optionally) perform side effects within an Action, and the work will be done in the background without blocking user interactions on the page. A Transition can include multiple Actions, and while a Transition is in progress, your UI stays responsive. For example, if the user clicks a tab but then changes their mind and clicks another tab, the second click will be immediately handled without waiting for the first update to finish. +The function passed to `startTransition` is called the "Action". You can update state and (optionally) perform side effects within an Action, and the work will be done in the background without blocking user interactions on the page. A Transition can include multiple Actions, and while a Transition is in progress, your UI stays responsive. For example, if the user clicks a tab but then changes their mind and clicks another tab, the second click will be immediately handled without waiting for the first update to finish. To give the user feedback about in-progress Transitions, the `isPending` state switches to `true` at the first call to `startTransition`, and stays `true` until all Actions complete and the final state is shown to the user. Transitions ensure side effects in Actions to complete in order to [prevent unwanted loading indicators](#preventing-unwanted-loading-indicators), and you can provide immediate feedback while the Transition is in progress with `useOptimistic`. @@ -597,7 +597,7 @@ export default function TabButton({ action, children, isActive }) {