From f8afd94cc927a6757c48f4763d8270f81088c065 Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 23 Apr 2024 22:27:11 -0400 Subject: [PATCH 01/35] Add /link/new-jsx-transform (#6772) --- vercel.json | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vercel.json b/vercel.json index 8d610c26e0..30b8e614a3 100644 --- a/vercel.json +++ b/vercel.json @@ -19,7 +19,6 @@ "destination": "/learn/rendering-lists#keeping-list-items-in-order-with-key", "permanent": false }, - { "source": "/link/invalid-hook-call", "destination": "/warnings/invalid-hook-call-warning", @@ -149,6 +148,11 @@ "source": "/link/setstate-in-render", "destination": "https://github.com/facebook/react/issues/18178#issuecomment-595846312", "permanent": false + }, + { + "source": "/link/new-jsx-transform", + "destination": "https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html", + "permanent": false } ], "headers": [ From cdd2fdd59fad857f55a820942c5a9e31794dafd8 Mon Sep 17 00:00:00 2001 From: Jack Pope Date: Wed, 24 Apr 2024 12:54:48 -0400 Subject: [PATCH 02/35] Add documentation for ref cleanup functions (#6770) * Add documentation for ref cleanup functions * Contain changes within canary block --- .../learn/manipulating-the-dom-with-refs.md | 87 ++++++++++++------- .../reference/react-dom/components/common.md | 25 +++++- 2 files changed, 79 insertions(+), 33 deletions(-) diff --git a/src/content/learn/manipulating-the-dom-with-refs.md b/src/content/learn/manipulating-the-dom-with-refs.md index bc9a3eac47..2d44d73535 100644 --- a/src/content/learn/manipulating-the-dom-with-refs.md +++ b/src/content/learn/manipulating-the-dom-with-refs.md @@ -218,18 +218,19 @@ This example shows how you can use this approach to scroll to an arbitrary node ```js -import { useRef } from 'react'; +import { useRef, useState } from "react"; export default function CatFriends() { const itemsRef = useRef(null); + const [catList, setCatList] = useState(setupCatList); - function scrollToId(itemId) { + function scrollToCat(cat) { const map = getMap(); - const node = map.get(itemId); + const node = map.get(cat); node.scrollIntoView({ - behavior: 'smooth', - block: 'nearest', - inline: 'center' + behavior: "smooth", + block: "nearest", + inline: "center", }); } @@ -244,34 +245,25 @@ export default function CatFriends() { return ( <>
    - {catList.map(cat => ( + {catList.map((cat) => (
  • { const map = getMap(); if (node) { - map.set(cat.id, node); + map.set(cat, node); } else { - map.delete(cat.id); + map.delete(cat); } }} > - {'Cat +
  • ))}
@@ -280,12 +272,13 @@ export default function CatFriends() { ); } -const catList = []; -for (let i = 0; i < 10; i++) { - catList.push({ - id: i, - imageUrl: 'https://placekitten.com/250/200?image=' + i - }); +function setupCatList() { + const catList = []; + for (let i = 0; i < 10; i++) { + catList.push("https://loremflickr.com/320/240/cat?lock=" + i); + } + + return catList; } ``` @@ -316,6 +309,16 @@ li { } ``` +```json package.json hidden +{ + "dependencies": { + "react": "canary", + "react-dom": "canary", + "react-scripts": "^5.0.0" + } +} +``` + In this example, `itemsRef` doesn't hold a single DOM node. Instead, it holds a [Map](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Map) from item ID to a DOM node. ([Refs can hold any values!](/learn/referencing-values-with-refs)) The [`ref` callback](/reference/react-dom/components/common#ref-callback) on every list item takes care to update the Map: @@ -327,10 +330,10 @@ In this example, `itemsRef` doesn't hold a single DOM node. Instead, it holds a const map = getMap(); if (node) { // Add to the Map - map.set(cat.id, node); + map.set(cat, node); } else { // Remove from the Map - map.delete(cat.id); + map.delete(cat); } }} > @@ -338,6 +341,28 @@ In this example, `itemsRef` doesn't hold a single DOM node. Instead, it holds a This lets you read individual DOM nodes from the Map later. + + +This example shows another approach for managing the Map with a `ref` callback cleanup function. + +```js +
  • { + const map = getMap(); + // Add to the Map + map.set(cat, node); + + return () => { + // Remove from the Map + map.delete(cat); + }; + }} +> +``` + + + ## Accessing another component's DOM nodes {/*accessing-another-components-dom-nodes*/} diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md index 610742735a..62ee08139d 100644 --- a/src/content/reference/react-dom/components/common.md +++ b/src/content/reference/react-dom/components/common.md @@ -257,11 +257,32 @@ React will also call your `ref` callback whenever you pass a *different* `ref` c #### Parameters {/*ref-callback-parameters*/} -* `node`: A DOM node or `null`. React will pass you the DOM node when the ref gets attached, and `null` when the ref gets detached. Unless you pass the same function reference for the `ref` callback on every render, the callback will get temporarily detached and re-attached during every re-render of the component. +* `node`: A DOM node or `null`. React will pass you the DOM node when the ref gets attached, and `null` when the `ref` gets detached. Unless you pass the same function reference for the `ref` callback on every render, the callback will get temporarily detached and re-attached during every re-render of the component. + + #### Returns {/*returns*/} -Do not return anything from the `ref` callback. +* **optional** `cleanup function`: When the `ref` is detached, React will call the cleanup function. If a function is not returned by the `ref` callback, React will call the callback again with `null` as the argument when the `ref` gets detached. + +```js + +
    { + console.log(node); + + return () => { + console.log('Clean up', node) + } +}}> + +``` + +#### Caveats {/*caveats*/} + +* When Strict Mode is on, React will **run one extra development-only setup+cleanup cycle** before the first real setup. This is a stress-test that ensures that your cleanup logic "mirrors" your setup logic and that it stops or undoes whatever the setup is doing. If this causes a problem, implement the cleanup function. +* When you pass a *different* `ref` callback, React will call the *previous* callback's cleanup function if provided. If not cleanup function is defined, the `ref` callback will be called with `null` as the argument. The *next* function will be called with the DOM node. + + --- From 9fb2f0dd12ef0babc9dc30c0eb984e49a94a9a20 Mon Sep 17 00:00:00 2001 From: Jan Kassens Date: Wed, 24 Apr 2024 15:58:09 -0400 Subject: [PATCH 03/35] Move `use` to APIs (#6774) --- src/content/reference/react/apis.md | 17 ++++++++++++++++ src/content/reference/react/hooks.md | 18 ----------------- src/content/reference/react/use.md | 30 ++++++++++++++-------------- src/sidebarReference.json | 10 +++++----- 4 files changed, 37 insertions(+), 38 deletions(-) diff --git a/src/content/reference/react/apis.md b/src/content/reference/react/apis.md index 9c14378703..4dd1d49ed1 100644 --- a/src/content/reference/react/apis.md +++ b/src/content/reference/react/apis.md @@ -15,3 +15,20 @@ In addition to [Hooks](/reference/react) and [Components](/reference/react/compo * [`lazy`](/reference/react/lazy) lets you defer loading a component's code until it's rendered for the first time. * [`memo`](/reference/react/memo) lets your component skip re-renders with same props. Used with [`useMemo`](/reference/react/useMemo) and [`useCallback`.](/reference/react/useCallback) * [`startTransition`](/reference/react/startTransition) lets you mark a state update as non-urgent. Similar to [`useTransition`.](/reference/react/useTransition) + +--- + +## Resource APIs {/*resource-apis*/} + +*Resources* can be accessed by a component without having them as part of their state. For example, a component can read a message from a Promise or read styling information from a context. + +To read a value from a resource, use this API: + +* [`use`](/reference/react/use) lets you read the value of a resource like a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or [context](/learn/passing-data-deeply-with-context). +```js +function MessageComponent({ messagePromise }) { + const message = use(messagePromise); + const theme = use(ThemeContext); + // ... +} +``` diff --git a/src/content/reference/react/hooks.md b/src/content/reference/react/hooks.md index cec71ce8f6..650a1c3826 100644 --- a/src/content/reference/react/hooks.md +++ b/src/content/reference/react/hooks.md @@ -106,24 +106,6 @@ To prioritize rendering, use one of these Hooks: --- -## Resource Hooks {/*resource-hooks*/} - -*Resources* can be accessed by a component without having them as part of their state. For example, a component can read a message from a Promise or read styling information from a context. - -To read a value from a resource, use this Hook: - -- [`use`](/reference/react/use) lets you read the value of a resource like a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or [context](/learn/passing-data-deeply-with-context). - -```js -function MessageComponent({ messagePromise }) { - const message = use(messagePromise); - const theme = use(ThemeContext); - // ... -} -``` - ---- - ## Other Hooks {/*other-hooks*/} These Hooks are mostly useful to library authors and aren't commonly used in the application code. diff --git a/src/content/reference/react/use.md b/src/content/reference/react/use.md index c3c8c92d2b..824fae32ef 100644 --- a/src/content/reference/react/use.md +++ b/src/content/reference/react/use.md @@ -5,13 +5,13 @@ canary: true -The `use` Hook is currently only available in React's Canary and experimental channels. Learn more about [React's release channels here](/community/versioning-policy#all-release-channels). +The `use` API is currently only available in React's Canary and experimental channels. Learn more about [React's release channels here](/community/versioning-policy#all-release-channels). -`use` is a React Hook that lets you read the value of a resource like a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or [context](/learn/passing-data-deeply-with-context). +`use` is a React API that lets you read the value of a resource like a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or [context](/learn/passing-data-deeply-with-context). ```js const value = use(resource); @@ -38,9 +38,9 @@ function MessageComponent({ messagePromise }) { // ... ``` -Unlike all other React Hooks, `use` can be called within loops and conditional statements like `if`. Like other React Hooks, the function that calls `use` must be a Component or Hook. +Unlike React Hooks, `use` can be called within loops and conditional statements like `if`. Like React Hooks, the function that calls `use` must be a Component or Hook. -When called with a Promise, the `use` Hook integrates with [`Suspense`](/reference/react/Suspense) and [error boundaries](/reference/react/Component#catching-rendering-errors-with-an-error-boundary). The component calling `use` *suspends* while the Promise passed to `use` is pending. If the component that calls `use` is wrapped in a Suspense boundary, the fallback will be displayed. Once the Promise is resolved, the Suspense fallback is replaced by the rendered components using the data returned by the `use` Hook. If the Promise passed to `use` is rejected, the fallback of the nearest Error Boundary will be displayed. +When called with a Promise, the `use` API integrates with [`Suspense`](/reference/react/Suspense) and [error boundaries](/reference/react/Component#catching-rendering-errors-with-an-error-boundary). The component calling `use` *suspends* while the Promise passed to `use` is pending. If the component that calls `use` is wrapped in a Suspense boundary, the fallback will be displayed. Once the Promise is resolved, the Suspense fallback is replaced by the rendered components using the data returned by the `use` API. If the Promise passed to `use` is rejected, the fallback of the nearest Error Boundary will be displayed. [See more examples below.](#usage) @@ -50,11 +50,11 @@ When called with a Promise, the `use` Hook integrates with [`Suspense`](/referen #### Returns {/*returns*/} -The `use` Hook returns the value that was read from the resource like the resolved value of a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or [context](/learn/passing-data-deeply-with-context). +The `use` API returns the value that was read from the resource like the resolved value of a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or [context](/learn/passing-data-deeply-with-context). #### Caveats {/*caveats*/} -* The `use` Hook must be called inside a Component or a Hook. +* The `use` API must be called inside a Component or a Hook. * When fetching data in a [Server Component](/reference/react/use-server), prefer `async` and `await` over `use`. `async` and `await` pick up rendering from the point where `await` was invoked, whereas `use` re-renders the component after the data is resolved. * Prefer creating Promises in [Server Components](/reference/react/use-server) and passing them to [Client Components](/reference/react/use-client) over creating Promises in Client Components. Promises created in Client Components are recreated on every render. Promises passed from a Server Component to a Client Component are stable across re-renders. [See this example](#streaming-data-from-server-to-client). @@ -230,7 +230,7 @@ export default function App() { } ``` -The Client Component then takes the Promise it received as a prop and passes it to the `use` Hook. This allows the Client Component to read the value from the Promise that was initially created by the Server Component. +The Client Component then takes the Promise it received as a prop and passes it to the `use` API. This allows the Client Component to read the value from the Promise that was initially created by the Server Component. ```js [[2, 6, "Message"], [4, 6, "messagePromise"], [4, 7, "messagePromise"], [5, 7, "use"]] // message.js @@ -243,7 +243,7 @@ export function Message({ messagePromise }) { return

    Here is the message: {messageContent}

    ; } ``` -Because `Message` is wrapped in [`Suspense`](/reference/react/Suspense), the fallback will be displayed until the Promise is resolved. When the Promise is resolved, the value will be read by the `use` Hook and the `Message` component will replace the Suspense fallback. +Because `Message` is wrapped in [`Suspense`](/reference/react/Suspense), the fallback will be displayed until the Promise is resolved. When the Promise is resolved, the value will be read by the `use` API and the `Message` component will replace the Suspense fallback. @@ -293,7 +293,7 @@ export default function App() { ```js src/index.js hidden // TODO: update to import from stable // react instead of canary once the `use` -// Hook is in a stable release of React +// API is in a stable release of React import React, { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import './styles.css'; @@ -334,7 +334,7 @@ When passing a Promise from a Server Component to a Client Component, its resolv #### Should I resolve a Promise in a Server or Client Component? {/*resolve-promise-in-server-or-client-component*/} -A Promise can be passed from a Server Component to a Client Component and resolved in the Client Component with the `use` Hook. You can also resolve the Promise in a Server Component with `await` and pass the required data to the Client Component as a prop. +A Promise can be passed from a Server Component to a Client Component and resolved in the Client Component with the `use` API. You can also resolve the Promise in a Server Component with `await` and pass the required data to the Client Component as a prop. ```js export default async function App() { @@ -360,7 +360,7 @@ In some cases a Promise passed to `use` could be rejected. You can handle reject #### Displaying an error to users with an error boundary {/*displaying-an-error-to-users-with-error-boundary*/} -If you'd like to display an error to your users when a Promise is rejected, you can use an [error boundary](/reference/react/Component#catching-rendering-errors-with-an-error-boundary). To use an error boundary, wrap the component where you are calling the `use` Hook in an error boundary. If the Promise passed to `use` is rejected the fallback for the error boundary will be displayed. +If you'd like to display an error to your users when a Promise is rejected, you can use an [error boundary](/reference/react/Component#catching-rendering-errors-with-an-error-boundary). To use an error boundary, wrap the component where you are calling the `use` API in an error boundary. If the Promise passed to `use` is rejected the fallback for the error boundary will be displayed. @@ -413,7 +413,7 @@ export default function App() { ```js src/index.js hidden // TODO: update to import from stable // react instead of canary once the `use` -// Hook is in a stable release of React +// API is in a stable release of React import React, { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import './styles.css'; @@ -474,9 +474,9 @@ To use the Promise's `catch` method, call Date: Thu, 25 Apr 2024 13:59:37 -0400 Subject: [PATCH 04/35] Rename useFormState to useActionState (#6776) * move useFormState api * add redirect * use React DOM as the name --- ...t-we-have-been-working-on-february-2024.md | 4 +- .../reference/react-dom/components/form.md | 12 ++--- .../reference/react-dom/hooks/index.md | 4 +- src/content/reference/react/hooks.md | 1 + src/content/reference/react/use-server.md | 8 +-- .../useActionState.md} | 54 ++++++++++--------- src/sidebarReference.json | 10 ++-- vercel.json | 5 ++ 8 files changed, 53 insertions(+), 45 deletions(-) rename src/content/reference/{react-dom/hooks/useFormState.md => react/useActionState.md} (72%) 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 03fc85c37f..04aff7afc8 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 @@ -52,7 +52,7 @@ We refer to this broader collection of features as simply "Actions". Actions all ``` -The `action` function can operate synchronously or asynchronously. You can define them on the client side using standard JavaScript or on the server with the [`'use server'`](/reference/react/use-server) directive. When using an action, React will manage the life cycle of the data submission for you, providing hooks like [`useFormStatus`](/reference/react-dom/hooks/useFormStatus), and [`useFormState`](/reference/react-dom/hooks/useFormState) to access the current state and response of the form action. +The `action` function can operate synchronously or asynchronously. You can define them on the client side using standard JavaScript or on the server with the [`'use server'`](/reference/react/use-server) directive. When using an action, React will manage the life cycle of the data submission for you, providing hooks like [`useFormStatus`](/reference/react-dom/hooks/useFormStatus), and [`useActionState`](/reference/react/useActionState) to access the current state and response of the form action. By default, Actions are submitted within a [transition](/reference/react/useTransition), keeping the current page interactive while the action is processing. Since Actions support async functions, we've also added the ability to use `async/await` in transitions. This allows you to show pending UI with the `isPending` state of a transition when an async request like `fetch` starts, and show the pending UI all the way through the update being applied. @@ -78,7 +78,7 @@ React Server Components, Asset Loading, Document Metadata, and Actions have all - **Asset Loading**: we integrated Suspense with the loading lifecycle of resources such as stylesheets, fonts, and scripts so that React takes them into account to determine whether the content in elements like [``), require careful positioning in the DOM due to style precedence rules. Building a stylesheet capability that allows for composability within components is hard, so users often end up either loading all of their styles far from the components that may depend on them, or they use a style library which encapsulates this complexity. + +In React 19, we're addressing this complexity and providing even deeper integration into Concurrent Rendering on the Client and Streaming Rendering on the Server with built in support for stylesheets. If you tell React the `precedence` of your stylesheet it will manage the insertion order of the stylesheet in the DOM and ensure that the stylesheet (if external) is loaded before revealing content that depends on those style rules. + +```js +function ComponentOne() { + return ( + + + +
    + High from ComponentOne +
    +
    + ) +} + +function ComponentTwo() { + return ( +
    + Hi from ComponentTwo + <-- will be inserted between foo & bar +
    + ) +} +``` + +During Server Side Rendering React will include the stylesheet in the ``, which ensures that the browser will not paint until it has loaded. If the stylesheet is discovered late after we've already started streaming, React will ensure that the stylesheet is inserted into the `` on the client before revealing the content of a Suspense boundary that depends on that stylesheet. + +During Client Side Rendering React will wait for newly rendered stylesheets to load before committing the render. + +If you render this component from multiple places within your application React will only include the stylesheet once in the document: +```js +function App() { + return <> + + ... + // won't lead to a duplicate stylesheet link in the DOM + +} +``` + +For users accustomed to loading stylesheets manually this is an opportunity to locate those stylesheets alongside the components that depend on them allowing for better local reasoning and an easier time ensuring you only load the stylesheets that you actually depend on. + +style libraries and style integrations with bundlers can also adopt this new capability so even if you don't directly render your own stylesheets, you can still benefit as your tools are upgraded to use this feature. + +For more details, read the docs for [``](/reference/react-dom/components/link) and [`