From f8afd94cc927a6757c48f4763d8270f81088c065 Mon Sep 17 00:00:00 2001 From: Ricky Date: Tue, 23 Apr 2024 22:27:11 -0400 Subject: [PATCH 1/3] 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 2/3] 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 3/3] 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