From 81f15204af726ea0711cd76f2c09aa7a24872a64 Mon Sep 17 00:00:00 2001 From: Brian Johnson Date: Mon, 30 Oct 2023 17:43:07 -0400 Subject: [PATCH 01/28] Adds Reference Overview Page (#6378) * Adds landing page for reference section.) * Updated hyperlinks. * Fixes Legacy APIs link. * Removes canary image from heading. --- src/content/reference/react/hooks.md | 139 +++++++++++++++++++++++++ src/content/reference/react/index.md | 149 ++++----------------------- src/sidebarReference.json | 6 +- 3 files changed, 164 insertions(+), 130 deletions(-) create mode 100644 src/content/reference/react/hooks.md diff --git a/src/content/reference/react/hooks.md b/src/content/reference/react/hooks.md new file mode 100644 index 000000000..cec71ce8f --- /dev/null +++ b/src/content/reference/react/hooks.md @@ -0,0 +1,139 @@ +--- +title: "Built-in React Hooks" +--- + + + +*Hooks* let you use different React features from your components. You can either use the built-in Hooks or combine them to build your own. This page lists all built-in Hooks in React. + + + +--- + +## State Hooks {/*state-hooks*/} + +*State* lets a component ["remember" information like user input.](/learn/state-a-components-memory) For example, a form component can use state to store the input value, while an image gallery component can use state to store the selected image index. + +To add state to a component, use one of these Hooks: + +* [`useState`](/reference/react/useState) declares a state variable that you can update directly. +* [`useReducer`](/reference/react/useReducer) declares a state variable with the update logic inside a [reducer function.](/learn/extracting-state-logic-into-a-reducer) + +```js +function ImageGallery() { + const [index, setIndex] = useState(0); + // ... +``` + +--- + +## Context Hooks {/*context-hooks*/} + +*Context* lets a component [receive information from distant parents without passing it as props.](/learn/passing-props-to-a-component) For example, your app's top-level component can pass the current UI theme to all components below, no matter how deep. + +* [`useContext`](/reference/react/useContext) reads and subscribes to a context. + +```js +function Button() { + const theme = useContext(ThemeContext); + // ... +``` + +--- + +## Ref Hooks {/*ref-hooks*/} + +*Refs* let a component [hold some information that isn't used for rendering,](/learn/referencing-values-with-refs) like a DOM node or a timeout ID. Unlike with state, updating a ref does not re-render your component. Refs are an "escape hatch" from the React paradigm. They are useful when you need to work with non-React systems, such as the built-in browser APIs. + +* [`useRef`](/reference/react/useRef) declares a ref. You can hold any value in it, but most often it's used to hold a DOM node. +* [`useImperativeHandle`](/reference/react/useImperativeHandle) lets you customize the ref exposed by your component. This is rarely used. + +```js +function Form() { + const inputRef = useRef(null); + // ... +``` + +--- + +## Effect Hooks {/*effect-hooks*/} + +*Effects* let a component [connect to and synchronize with external systems.](/learn/synchronizing-with-effects) This includes dealing with network, browser DOM, animations, widgets written using a different UI library, and other non-React code. + +* [`useEffect`](/reference/react/useEffect) connects a component to an external system. + +```js +function ChatRoom({ roomId }) { + useEffect(() => { + const connection = createConnection(roomId); + connection.connect(); + return () => connection.disconnect(); + }, [roomId]); + // ... +``` + +Effects are an "escape hatch" from the React paradigm. Don't use Effects to orchestrate the data flow of your application. If you're not interacting with an external system, [you might not need an Effect.](/learn/you-might-not-need-an-effect) + +There are two rarely used variations of `useEffect` with differences in timing: + +* [`useLayoutEffect`](/reference/react/useLayoutEffect) fires before the browser repaints the screen. You can measure layout here. +* [`useInsertionEffect`](/reference/react/useInsertionEffect) fires before React makes changes to the DOM. Libraries can insert dynamic CSS here. + +--- + +## Performance Hooks {/*performance-hooks*/} + +A common way to optimize re-rendering performance is to skip unnecessary work. For example, you can tell React to reuse a cached calculation or to skip a re-render if the data has not changed since the previous render. + +To skip calculations and unnecessary re-rendering, use one of these Hooks: + +- [`useMemo`](/reference/react/useMemo) lets you cache the result of an expensive calculation. +- [`useCallback`](/reference/react/useCallback) lets you cache a function definition before passing it down to an optimized component. + +```js +function TodoList({ todos, tab, theme }) { + const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]); + // ... +} +``` + +Sometimes, you can't skip re-rendering because the screen actually needs to update. In that case, you can improve performance by separating blocking updates that must be synchronous (like typing into an input) from non-blocking updates which don't need to block the user interface (like updating a chart). + +To prioritize rendering, use one of these Hooks: + +- [`useTransition`](/reference/react/useTransition) lets you mark a state transition as non-blocking and allow other updates to interrupt it. +- [`useDeferredValue`](/reference/react/useDeferredValue) lets you defer updating a non-critical part of the UI and let other parts update first. + +--- + +## 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. + +- [`useDebugValue`](/reference/react/useDebugValue) lets you customize the label React DevTools displays for your custom Hook. +- [`useId`](/reference/react/useId) lets a component associate a unique ID with itself. Typically used with accessibility APIs. +- [`useSyncExternalStore`](/reference/react/useSyncExternalStore) lets a component subscribe to an external store. + +--- + +## Your own Hooks {/*your-own-hooks*/} + +You can also [define your own custom Hooks](/learn/reusing-logic-with-custom-hooks#extracting-your-own-custom-hook-from-a-component) as JavaScript functions. diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index cec71ce8f..452f326d2 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -1,139 +1,30 @@ --- -title: "Built-in React Hooks" +title: React Reference Overview --- - -*Hooks* let you use different React features from your components. You can either use the built-in Hooks or combine them to build your own. This page lists all built-in Hooks in React. - +This section provides detailed reference documentation for working with React. +For an introduction to React, please visit the [Learn](/learn) section. ---- - -## State Hooks {/*state-hooks*/} - -*State* lets a component ["remember" information like user input.](/learn/state-a-components-memory) For example, a form component can use state to store the input value, while an image gallery component can use state to store the selected image index. - -To add state to a component, use one of these Hooks: - -* [`useState`](/reference/react/useState) declares a state variable that you can update directly. -* [`useReducer`](/reference/react/useReducer) declares a state variable with the update logic inside a [reducer function.](/learn/extracting-state-logic-into-a-reducer) - -```js -function ImageGallery() { - const [index, setIndex] = useState(0); - // ... -``` - ---- - -## Context Hooks {/*context-hooks*/} - -*Context* lets a component [receive information from distant parents without passing it as props.](/learn/passing-props-to-a-component) For example, your app's top-level component can pass the current UI theme to all components below, no matter how deep. - -* [`useContext`](/reference/react/useContext) reads and subscribes to a context. - -```js -function Button() { - const theme = useContext(ThemeContext); - // ... -``` - ---- - -## Ref Hooks {/*ref-hooks*/} - -*Refs* let a component [hold some information that isn't used for rendering,](/learn/referencing-values-with-refs) like a DOM node or a timeout ID. Unlike with state, updating a ref does not re-render your component. Refs are an "escape hatch" from the React paradigm. They are useful when you need to work with non-React systems, such as the built-in browser APIs. - -* [`useRef`](/reference/react/useRef) declares a ref. You can hold any value in it, but most often it's used to hold a DOM node. -* [`useImperativeHandle`](/reference/react/useImperativeHandle) lets you customize the ref exposed by your component. This is rarely used. - -```js -function Form() { - const inputRef = useRef(null); - // ... -``` - ---- - -## Effect Hooks {/*effect-hooks*/} - -*Effects* let a component [connect to and synchronize with external systems.](/learn/synchronizing-with-effects) This includes dealing with network, browser DOM, animations, widgets written using a different UI library, and other non-React code. - -* [`useEffect`](/reference/react/useEffect) connects a component to an external system. - -```js -function ChatRoom({ roomId }) { - useEffect(() => { - const connection = createConnection(roomId); - connection.connect(); - return () => connection.disconnect(); - }, [roomId]); - // ... -``` +Our The React reference documentation is broken down into functional subsections: -Effects are an "escape hatch" from the React paradigm. Don't use Effects to orchestrate the data flow of your application. If you're not interacting with an external system, [you might not need an Effect.](/learn/you-might-not-need-an-effect) +## React {/*react*/} +Programmatic React features: +* [Hooks](/reference/react/hooks) - Use different React features from your components. +* [Components](/reference/react/components) - Documents built-in components that you can use in your JSX. +* [APIs](/reference/react/apis) - APIs that are useful for defining components. +* [Directives](/reference/react/directives) - Provide instructions to bundlers compatible with React Server Components. -There are two rarely used variations of `useEffect` with differences in timing: - -* [`useLayoutEffect`](/reference/react/useLayoutEffect) fires before the browser repaints the screen. You can measure layout here. -* [`useInsertionEffect`](/reference/react/useInsertionEffect) fires before React makes changes to the DOM. Libraries can insert dynamic CSS here. - ---- - -## Performance Hooks {/*performance-hooks*/} - -A common way to optimize re-rendering performance is to skip unnecessary work. For example, you can tell React to reuse a cached calculation or to skip a re-render if the data has not changed since the previous render. - -To skip calculations and unnecessary re-rendering, use one of these Hooks: - -- [`useMemo`](/reference/react/useMemo) lets you cache the result of an expensive calculation. -- [`useCallback`](/reference/react/useCallback) lets you cache a function definition before passing it down to an optimized component. - -```js -function TodoList({ todos, tab, theme }) { - const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]); - // ... -} -``` - -Sometimes, you can't skip re-rendering because the screen actually needs to update. In that case, you can improve performance by separating blocking updates that must be synchronous (like typing into an input) from non-blocking updates which don't need to block the user interface (like updating a chart). - -To prioritize rendering, use one of these Hooks: - -- [`useTransition`](/reference/react/useTransition) lets you mark a state transition as non-blocking and allow other updates to interrupt it. -- [`useDeferredValue`](/reference/react/useDeferredValue) lets you defer updating a non-critical part of the UI and let other parts update first. - ---- - -## 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. - -- [`useDebugValue`](/reference/react/useDebugValue) lets you customize the label React DevTools displays for your custom Hook. -- [`useId`](/reference/react/useId) lets a component associate a unique ID with itself. Typically used with accessibility APIs. -- [`useSyncExternalStore`](/reference/react/useSyncExternalStore) lets a component subscribe to an external store. - ---- +## React DOM {/*react-dom*/} +React-dom contains features that are only supported for web applications +(which run in the browser DOM environment). This section is broken into the following: -## Your own Hooks {/*your-own-hooks*/} +* [Hooks](/reference/react-dom/hooks) - Hooks for web applications which run in the browser DOM environment. +* [Components](/reference/react-dom/components) - React supports all of the browser built-in HTML and SVG components. +* [APIs](/reference/react-dom) - The `react-dom` package contains methods supported only in web applications. +* [Client APIs](/reference/react-dom/client) - The `react-dom/client` APIs let you render React components on the client (in the browser). +* [Server APIs](/reference/react-dom/server) - The `react-dom/server` APIs let you render React components to HTML on the server. -You can also [define your own custom Hooks](/learn/reusing-logic-with-custom-hooks#extracting-your-own-custom-hook-from-a-component) as JavaScript functions. +## Legacy APIs {/*legacy-apis*/} +* [Legacy APIs](/reference/react/legacy) - Exported from the react package, but not recommended for use in newly written code. \ No newline at end of file diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 79b1fb9f7..5a6556557 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -6,9 +6,13 @@ "hasSectionHeader": true, "sectionHeader": "react@18.2.0" }, + { + "title": "Overview", + "path": "/reference/react" + }, { "title": "Hooks", - "path": "/reference/react", + "path": "/reference/react/hooks", "routes": [ { "title": "use", From 49c2d7865ba75e9e83526c2e5ec5decc97c014aa Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 30 Oct 2023 17:49:11 -0400 Subject: [PATCH 02/28] 'use server' fleshing out (#6384) Co-authored-by: Sophie Alpert Co-authored-by: Luna Wei --- src/content/reference/react/use-server.md | 190 ++++++++++++++++++++-- 1 file changed, 174 insertions(+), 16 deletions(-) diff --git a/src/content/reference/react/use-server.md b/src/content/reference/react/use-server.md index cc271669a..beaeb5f34 100644 --- a/src/content/reference/react/use-server.md +++ b/src/content/reference/react/use-server.md @@ -25,34 +25,192 @@ canary: true ### `'use server'` {/*use-server*/} -Add `'use server';` at the very top of an async function to mark that the function can be executed by the client. +Add `'use server'` at the top of an async function body to mark the function as callable by the client. We call these functions _server actions_. -```js +```js {2} async function addToCart(data) { 'use server'; // ... } - -// ``` -This function can be passed to the client. When called on the client, it will make a network request to the server that includes a serialized copy of any arguments passed. If the server function returns a value, that value will be serialized and returned to the client. +When calling a server action on the client, it will make a network request to the server that includes a serialized copy of any arguments passed. If the server action returns a value, that value will be serialized and returned to the client. -Alternatively, add `'use server';` at the very top of a file to mark all exports within that file as async server functions that can be used anywhere, including imported in client component files. +Instead of individually marking functions with `'use server'`, you can add the directive to the top of a file to mark all exports within that file as server actions that can be used anywhere, including imported in client code. #### Caveats {/*caveats*/} +* `'use server'` must be at the very beginning of their function or module; above any other code including imports (comments above directives are OK). They must be written with single or double quotes, not backticks. +* `'use server'` can only be used in server-side files. The resulting server actions can be passed to Client Components through props. See supported [types for serialization](#serializable-parameters-and-return-values). +* To import a server action from [client code](/reference/react/use-client), the directive must be used on a module level. +* Because the underlying network calls are always asynchronous, `'use server'` can only be used on async functions. +* Always treat arguments to server actions as untrusted input and authorize any mutations. See [security considerations](#security). +* Server actions should be called in a [transition](/reference/react/useTransition). Server actions passed to [`
`](/reference/react-dom/components/form#props) or [`formAction`](/reference/react-dom/components/input#props) will automatically be called in a transition. +* Server actions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing server actions typically process one action at a time and do not have a way to cache the return value. -* Remember that parameters to functions marked with `'use server'` are fully client-controlled. For security, always treat them as untrusted input, making sure to validate and escape the arguments as appropriate. -* To avoid the confusion that might result from mixing client- and server-side code in the same file, `'use server'` can only be used in server-side files; the resulting functions can be passed to client components through props. -* Because the underlying network calls are always asynchronous, `'use server'` can be used only on async functions. -* Directives like `'use server'` must be at the very beginning of their function or file, above any other code including imports (comments above directives are OK). They must be written with single or double quotes, not backticks. (The `'use xyz'` directive format somewhat resembles the `useXyz()` Hook naming convention, but the similarity is coincidental.) +### Security considerations {/*security*/} -## Usage {/*usage*/} +Arguments to server actions are fully client-controlled. For security, always treat them as untrusted input, and make sure to validate and escape arguments as appropriate. + +In any server action, make sure to validate that the logged-in user is allowed to perform that action. -This section is a work in progress. -This API can be used in any framework that supports React Server Components. You may find additional documentation from them. -* [Next.js documentation](https://nextjs.org/docs/getting-started/react-essentials) -* More coming soon - \ No newline at end of file +To prevent sending sensitive data from a server action, there are experimental taint APIs to prevent unique values and objects from being passed to client code. + +See [experimental_taintUniqueValue](/reference/react/experimental_taintUniqueValue) and [experimental_taintObjectReference](/reference/react/experimental_taintObjectReference). + + + +### Serializable arguments and return values {/*serializable-parameters-and-return-values*/} + +As client code calls the server action over the network, any arguments passed will need to be serializable. + +Here are supported types for server action arguments: + +* Primitives + * [string](https://developer.mozilla.org/en-US/docs/Glossary/String) + * [number](https://developer.mozilla.org/en-US/docs/Glossary/Number) + * [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) + * [boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean) + * [undefined](https://developer.mozilla.org/en-US/docs/Glossary/Undefined) + * [null](https://developer.mozilla.org/en-US/docs/Glossary/Null) + * [symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol), only symbols registered in the global Symbol registry via [`Symbol.for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for) +* Iterables containing serializable values + * [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) + * [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) + * [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) + * [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) + * [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) +* [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) +* [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) +* [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) instances +* Plain [objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object): those created with [object initializers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer), with serializable properties +* Functions that are server actions +* [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) + +Notably, these are not supported: +* React elements, or [JSX](https://react.dev/learn/writing-markup-with-jsx) +* Functions, including component functions or any other function that is not a server action +* [Classes](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Classes_in_JavaScript) +* Objects that are instances of any class (other than built-ins mentioned) or objects with [null-prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects) +* Symbols not registered globally, ex. `Symbol('my new symbol')` + + +Supported serializable return values are the same as [serializable props](/reference/react/use-client#passing-props-from-server-to-client-components) for a boundary Client Component. + + +## Usage {/*usage*/} + +### Server actions in forms {/*server-actions-in-forms*/} + +The most common use case of server actions will be calling server functions that mutate data. On the browser, the [HTML form element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) is the traditional approach for a user to submit a mutation. With React Server Components, React introduces first-class support for server actions in [forms](/reference/react-dom/components/form). + +Here is a form that allows a user to request a username. + +```js [[1, 3, "formData"]] +// App.js + +async function requestUsername(formData) { + 'use server'; + const username = formData.get('username'); + // ... +} + +export default App() { + + + +
+} +``` + +In this example `requestUsername` is a server action passed to a `
`. When a user submits this form, there is a network request to the server function `requestUsername`. When calling a server action in a form, React will supply the form's [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) as the first argument to the server action. + +By passing a server action to the form `action`, React can [progressively enhance](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement) the form. This means that forms can be submitted before the JavaScript bundle is loaded. + +#### Handling return values in forms {/*handling-return-values*/} + +In the username request form, there might be the chance that a username is not available. `requestUsername` should tell us if it fails or not. + +To update the UI based on the result of a server action while supporting progressive enhancement, use [`useFormState`](/reference/react-dom/hooks/useFormState). + +```js +// requestUsername.js +'use server'; + +export default async function requestUsername(formData) { + const username = formData.get('username'); + if (canRequest(username)) { + // ... + return 'successful'; + } + return 'failed'; +} +``` + +```js {4,8}, [[2, 2, "'use client'"]] +// UsernameForm.js +'use client'; + +import {useFormState} from 'react-dom'; +import requestUsername from './requestUsername'; + +function UsernameForm() { + const [returnValue, action] = useFormState(requestUsername, 'n/a'); + + return ( + <> + + + +
+

Last submission request returned: {returnValue}

+ + ); +} +``` + +Note that like most Hooks, `useFormState` can only be called in [client code](/reference/react/use-client). + +### Calling a server action outside of `
` {/*calling-a-server-action-outside-of-form*/} + +Server actions are exposed server endpoints and can be called anywhere in client code. + +When using a server action outside of a [form](/reference/react-dom/components/form), call the server action in a [transition](/reference/react/useTransition), which allows you to display a loading indicator, show [optimistic state updates](/reference/react/useOptimistic), and handle unexpected errors. Forms will automatically wrap server actions in transitions. + +```js {9-12} +import incrementLike from './actions'; +import { useState, useTransition } from 'react'; + +function LikeButton() { + const [isPending, startTransition] = useTransition(); + const [likeCount, setLikeCount] = useState(0); + + const onClick = () => { + startTransition(async () => { + const currentCount = await incrementLike(); + setLikeCount(currentCount); + }); + }; + + return ( + <> +

Total Likes: {likeCount}

+ ; + + ); +} +``` + +```js +// actions.js +'use server'; + +let likeCount = 0; +export default async incrementLike() { + likeCount++; + return likeCount; +} +``` + +To read a server action return value, you'll need to `await` the promise returned. \ No newline at end of file From 9c60167bf966286bafb99492e31b0609ccb56b5c Mon Sep 17 00:00:00 2001 From: Luna Date: Mon, 30 Oct 2023 18:03:51 -0400 Subject: [PATCH 03/28] 'use client' - flesh out usages and reference (#6362) Co-authored-by: Soichiro Miki Co-authored-by: David McCabe Co-authored-by: Luna Wei --- .../use_client_module_dependency.dark.png | Bin 0 -> 18311 bytes .../diagrams/use_client_module_dependency.png | Bin 0 -> 18236 bytes .../diagrams/use_client_render_tree.dark.png | Bin 0 -> 13583 bytes .../docs/diagrams/use_client_render_tree.png | Bin 0 -> 13713 bytes src/content/reference/react/directives.md | 2 +- src/content/reference/react/use-client.md | 353 +++++++++++++++++- 6 files changed, 335 insertions(+), 20 deletions(-) create mode 100644 public/images/docs/diagrams/use_client_module_dependency.dark.png create mode 100644 public/images/docs/diagrams/use_client_module_dependency.png create mode 100644 public/images/docs/diagrams/use_client_render_tree.dark.png create mode 100644 public/images/docs/diagrams/use_client_render_tree.png diff --git a/public/images/docs/diagrams/use_client_module_dependency.dark.png b/public/images/docs/diagrams/use_client_module_dependency.dark.png new file mode 100644 index 0000000000000000000000000000000000000000..c50e7308b08fac14aea09cb7b1e8817ef5ba7a02 GIT binary patch literal 18311 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 FVE3yjM@;8x1#p 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 literal 0 HcmV?d00001 diff --git a/public/images/docs/diagrams/use_client_module_dependency.png b/public/images/docs/diagrams/use_client_module_dependency.png new file mode 100644 index 0000000000000000000000000000000000000000..d535246f7f976316cb04096c7ac1fa4afd884e92 GIT binary patch literal 18236 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 b|1CFHb literal 0 HcmV?d00001 diff --git a/public/images/docs/diagrams/use_client_render_tree.dark.png b/public/images/docs/diagrams/use_client_render_tree.dark.png new file mode 100644 index 0000000000000000000000000000000000000000..8d3e6a4849ef7298eaea29b3690672d6b75de8c0 GIT binary patch literal 13583 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 OM_xurx=6~v_kRIPAXE1M literal 0 HcmV?d00001 diff --git a/public/images/docs/diagrams/use_client_render_tree.png b/public/images/docs/diagrams/use_client_render_tree.png new file mode 100644 index 0000000000000000000000000000000000000000..ad3840681cc807f733680710ea47b9563b769c26 GIT binary patch literal 13713 zcmcJ$byQnl*De|;(iSbHO$((sEgD+fOR?fw9D=(P3IqvKrMQ;hR@~i5aA|PY;1qWW zenNlm`@P@!?mc6i`^Oz)uk1DFGv_nsURir)Wv?VaMM;L}KE-_i06--BPErj3zySjQ z*qnFoU^JF)+)J1fj-|MwH~>%@MsR72i;=NDs>!?s6!kq@#|Za6ywmvz01!O9ZCHT# z#3vX7w2Fd;l*|VOfY&d8UpBxm1>l(h@XWjwJ%0h9zX0wj01pgQ4Dd?-i>3oSF~=`} zSH|suvAngv6-6MSxAwOph6JNe!{~+GgKkmG;gJFGNXM9ox`qCw`Wphn;PLB?U)US> zus0vVgdxGguE7`*5w}oL2<8YDb_)`84P=ExbGk)}x`n*)48!Pequd5czdrtRb8~|s z7jX-r3CM?!jlD^z^Q~_8YZ%FfpPG|~hX&FvnBA-atU+CNkvX#(@-c8?rOnvL??Q+sFUR_0QA zXT#gZQ+j87YuXXBYbw8*I3tStP}8KJvpJ(Gd>aS*SGP$$lKN0nb2~>WskKJgjg;-gl|_9+9FQoLUx=dqLC)}!u=a7s;^wfX?*5gX;{L(n(WS7qah0^1yB?|3 z?y)2uNdz7#0&bxKkT3$zl;XZ2a85(t>~zW4VoGP9a#{^Ix1o4!=|d&5cytlRGmX+C z?lmL=$1|M+63GJz=Y@oGMwBS0)~ck|I94K4I{Lr`?TE3lCe)f=S>)n}qrf z@KPFPVu-k?DX9Z?X=vt*5PolHQb|9M&KZTLAUOMX!w@PdoW6d=Z+!bdeCY2FN?fP+s`#F}xfy&w*Vz8&fD9 z-f_HF%8yjPV`gA1?m}E=`(1$4B&{jxjv4f%jK*`?c6D-sjG)KJ&(6!p!tk<*?cfNY zvwGLq!my#q1t+NCO-ygl7asN6^sa|EX5$irT)ZG#118QlF{4s*Gw=eUHlk!Yn$~(5 z`!5#<->DdAS`SP*=izpDgR<{-vC)nxFySaacmrM|0Gwm{!3Ti14RC}D@J<8$ZMVQ% z@ZWX|e1rdOsUW}_fj8D|djkdx0MD^+n;#sI3Od5QZGc-~jo`NVaqS|F3^s;<0PE8g zu7!{51b!74LnP-zzd!)B9prbFsUzGsb>0!fFjU=Xit9Nx%`Du`!+O%&$>QOYb8P)& z_}1?-JBSd<7awC7?;YVKeO1Xbevuso{cπy1S0Fw!_o>-}R6ydeMZ9neX2;rLv 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 O0J2g_l0|QgKL0Nyz#cOI literal 0 HcmV?d00001 diff --git a/src/content/reference/react/directives.md b/src/content/reference/react/directives.md index b323dab1d..4854310b3 100644 --- a/src/content/reference/react/directives.md +++ b/src/content/reference/react/directives.md @@ -19,5 +19,5 @@ Directives provide instructions to [bundlers compatible with React Server Compon ## Source code directives {/*source-code-directives*/} -* [`'use client'`](/reference/react/use-client) marks source files whose components execute on the client. +* [`'use client'`](/reference/react/use-client) lets you mark what code runs on the client. * [`'use server'`](/reference/react/use-server) marks server-side functions that can be called from client-side code. \ No newline at end of file diff --git a/src/content/reference/react/use-client.md b/src/content/reference/react/use-client.md index b1ba1d7ae..e0190d3fe 100644 --- a/src/content/reference/react/use-client.md +++ b/src/content/reference/react/use-client.md @@ -12,7 +12,7 @@ canary: true -`'use client'` marks source files whose components execute on the client. +`'use client'` lets you mark what code runs on the client. @@ -24,37 +24,352 @@ canary: true ### `'use client'` {/*use-client*/} -Add `'use client';` at the very top of a file to mark that the file (including any child components it uses) executes on the client, regardless of where it's imported. +Add `'use client'` at the top of a file to mark the module and its transitive dependencies as client code. -```js +```js {1} 'use client'; import { useState } from 'react'; +import { formatDate } from './formatters'; +import Link from './link'; export default function RichTextEditor(props) { + formatDate(); // ... + return + + // ... +} ``` -When a file marked `'use client'` is imported from a server component, [compatible bundlers](/learn/start-a-new-react-project#bleeding-edge-react-frameworks) will treat the import as the "cut-off point" between server-only code and client code. Components at or below this point in the module graph can use client-only React features like [`useState`](/reference/react/useState). +When a file marked with `'use client'` is imported from a Server Component, [compatible bundlers](/learn/start-a-new-react-project#bleeding-edge-react-frameworks) will treat the module import as a boundary between server-run and client-run code. + +As a dependency of `RichTextEditor`, `formatDate` and `Link` will also be evaluated on the client regardless of whether their modules contain a `'use client'` directive. Note that the same module may be evaluated on the server when imported from server code and on the client when imported from client code. #### Caveats {/*caveats*/} -* It's not necessary to add `'use client'` to every file that uses client-only React features, only the files that are imported from server component files. `'use client'` denotes the _boundary_ between server-only and client code; any components further down the tree will automatically be executed on the client. In order to be rendered from server components, components exported from `'use client'` files must have serializable props. -* When a `'use client'` file is imported from a server file, the imported values can be rendered as a React component or passed via props to a client component. Any other use will throw an exception. -* When a `'use client'` file is imported from another client file, the directive has no effect. This allows you to write client-only components that are simultaneously usable from server and client components. -* All the code in `'use client'` file as well as any modules it imports (directly or indirectly) will become a part of the client module graph and must be sent to and executed by the client in order to be rendered by the browser. To reduce client bundle size and take full advantage of the server, move state (and the `'use client'` directives) lower in the tree when possible, and pass rendered server components [as children](/learn/passing-props-to-a-component#passing-jsx-as-children) to client components. -* Because props are serialized across the server–client boundary, note that the placement of these directives can affect the amount of data sent to the client; avoid data structures that are larger than necessary. -* Components like a `` that use neither server-only nor client-only features should generally not be marked with `'use client'`. That way, they can render exclusively on the server when used from a server component, but they'll be added to the client bundle when used from a client component. -* Libraries published to npm should include `'use client'` on exported React components that can be rendered with serializable props that use client-only React features, to allow those components to be imported and rendered by server components. Otherwise, users will need to wrap library components in their own `'use client'` files which can be cumbersome and prevents the library from moving logic to the server later. When publishing prebundled files to npm, ensure that `'use client'` source files end up in a bundle marked with `'use client'`, separate from any bundle containing exports that can be used directly on the server. -* Client components will still run as part of server-side rendering (SSR) or build-time static site generation (SSG), which act as clients to transform React components' initial render output to HTML that can be rendered before JavaScript bundles are downloaded. But they can't use server-only features like reading directly from a database. -* Directives like `'use client'` must be at the very beginning of a file, above any imports or other code (comments above directives are OK). They must be written with single or double quotes, not backticks. (The `'use xyz'` directive format somewhat resembles the `useXyz()` Hook naming convention, but the similarity is coincidental.) +* `'use client'` must be at the very beginning of a file, above any imports or other code (comments are OK). They must be written with single or double quotes, but not backticks. +* When a `'use client'` module is imported from another client-rendered module, the directive has no effect. +* When a component module contains a `'use client'` directive, any usage of that component is guaranteed to be a Client Component. However, a component can still be evaluated on the client even if it does not have a `'use client'` directive. + * A component usage is considered a Client Component if it is defined in module with `'use client'` directive or when it is a transitive dependency of a module that contains a `'use client'` directive. Otherwise, it is a Server Component. +* Code that is marked for client evaluation is not limited to components. All code that is a part of the client module sub-tree is sent to and run by the client. +* When a server evaluated module imports values from a `'use client'` module, the values must either be a React component or [supported serializable prop values](#passing-props-from-server-to-client-components) to be passed to a Client Component. Any other use case will throw an exception. + +### How `'use client'` marks client code {/*how-use-client-marks-client-code*/} + +In a React app, components are often split into separate files, or [modules](/learn/importing-and-exporting-components#exporting-and-importing-a-component). + +For apps that use React Server Components, the app is server-rendered by default. `'use client'` introduces a server-client boundary in the [module dependency tree](/learn/understanding-your-ui-as-a-tree#the-module-dependency-tree), effectively creating a client-module subtree. + +To better illustrate this, consider the following React Server Component app and its module dependency and render tree. + + + +```js App.js +import FancyText from './FancyText'; +import InspirationGenerator from './InspirationGenerator'; +import Copyright from './Copyright'; + +export default function App() { + return ( + <> + + + + + + ); +} + +``` + +```js FancyText.js +export default function FancyText({title, text}) { + return title + ?

{text}

+ :

{text}

+} +``` + +```js InspirationGenerator.js +'use client'; + +import { useState } from 'react'; +import inspirations from './inspirations'; +import FancyText from './FancyText'; + +export default function InspirationGenerator({children}) { + const [index, setIndex] = useState(0); + const quote = inspirations[index]; + const next = () => setIndex((index + 1) % inspirations.length); + + return ( + <> +

Your inspirational quote is:

+ + + {children} + + ); +} +``` + +```js Copyright.js +export default function Copyright({year}) { + return

©️ {year}

; +} +``` + +```js inspirations.js +export default [ + "Don’t let yesterday take up too much of today.” — Will Rogers", + "Ambition is putting a ladder against the sky.", + "A joy that's shared is a joy made double.", +]; +``` + +```css +.fancy { + font-family: 'Georgia'; +} +.title { + color: #007AA3; + text-decoration: underline; +} +.cursive { + font-style: italic; +} +.small { + font-size: 10px; +} +``` + +
+ + +`'use client'` segments the module dependency tree of the React Server Components app to mark `InspirationGenerator.js` and any of its dependencies as client-rendered. + + +In the module dependency tree of the example app, the `'use client'` directive in `InspirationGenerator.js` marks that module and all of its transitive dependencies as client modules. It creates a subtree of client modules with `InspirationGenerator.js` as the root. + +During render, the framework will server-render the root component and continue through the [render tree](/learn/understanding-your-ui-as-a-tree#the-render-tree), opting-out of evaluating any code imported from client-marked code. + +The server-rendered portion of the render tree is then sent to the client. The client, with its client code downloaded, then completes rendering the rest of the tree. + + +The render tree for the React Server Components app. `InspirationGenerator` and its child component `FancyText` are components exported from client-marked code and considered Client Components. + + +We introduce the following definitions: + +* **Client Components** are components in a render tree that are rendered on the client. +* **Server Components** are components in a render tree that are rendered on the server. + +Working through the example app, `App`, `FancyText` and `Copyright` are all server-rendered and considered Server Components. As `InspirationGenerator.js` and its transitive dependencies are marked as client code, the component `InspirationGenerator` and its child component `FancyText` are Client Components. + + +#### How is `FancyText` both a Server and a Client Component? {/*how-is-fancytext-both-a-server-and-a-client-component*/} + +By the above definitions, the component `FancyText` is both a Server and Client Component, how can that be? + +First, let's clarify that the term "component" is not very precise. Here are just two ways "component" can be understood: + +1. A "component" can refer to a **component definition**. In most cases this will be a function. + +```js +// This is a definition of a component +function MyComponent() { + return

My Component

+} +``` + +2. A "component" can also refer to a **component usage** of its definition. +```js +import MyComponent from './MyComponent'; + +function App() { + // This is a usage of a component + return ; +} +``` + +Often, the imprecision is not important when explaining concepts, but in this case it is. + +When we talk about Server or Client Components, we are referring to component usages. + +* If the component is defined in a module with a `'use client'` directive, or the component is imported and called in a Client Component, then the component usage is a Client Component. +* Otherwise, the component usage is a Server Component. + + +A render tree illustrates component usages. + +Back to the question of `FancyText`, we see that the component definition does _not_ have a `'use client'` directive and it has two usages. + +The usage of `FancyText` as a child of `App`, marks that usage as a Server Component. When `FancyText` is imported and called under `InspirationGenerator`, that usage of `FancyText` is a Client Component as `InspirationGenerator` contains a `'use client'` directive. + +This means that the component definition for `FancyText` will both be evaluated on the server and also downloaded by the client to render its Client Component usage. + +
+ + + +#### Why is `Copyright` a Server Component? {/*why-is-copyright-a-server-component*/} + +As a child of `InspirationGenerator`, a Client Component, why is `Copyright` a Server Component? + +To clarify, `'use client'` defines the boundary between server and client code on the _module dependency tree_, not the render tree. + + +`'use client'` defines the boundary between server and client code on the module dependency tree. + + +In the module dependency tree, we see that `App.js` imports and calls `Copyright` from the `Copyright.js` module. As `Copyright.js` does not contain a `'use client'` directive, the component usage is rendered on the server. `App` is rendered on the server as it is the root component. + +Client Components can render Server Components because you can pass JSX as props. In this case, `InspirationGenerator` receives `Copyright` as [children](/learn/passing-props-to-a-component#passing-jsx-as-children). However, the `InspirationGenerator` module never directly imports the `Copyright` module nor calls the component, all of that is done by `App`. + +The takeaway is that a parent-child render relationship between components does not guarantee the same render environment. + + + +### When to use `'use client'` {/*when-to-use-use-client*/} + +With `'use client'`, you can determine what component usages will be Client Components. As Server Components are default, here is a brief overview of the advantages and limitations to Server Components to determine when you need to mark something as client rendered. + +For simplicity, we talk about Server Components, but the same principles apply to all code in your app that is server run. + +#### Advantages {/*advantages*/} +* Server Components can reduce the amount of code sent and run by the client. Only client modules are bundled and evaluated by the client. +* Server Components benefit from running on the server. They can access the local filesystem and may experience low latency for data fetches and network requests. + +#### Limitations {/*limitations*/} +* Server Components cannot support interaction as event handlers must be registered and triggered by a client. + * The browser, as an example client, is responsible for delegating UI clicks to the appropriate `onClick` handler. +* Server Components cannot use most Hooks. + * When Server Components are rendered, they are conceptually resolved into instructions for the client to interpret and turn into UI primitives. This means that Server Components do not persist in memory after render and do not support re-rendering or state. + +### Passing props from Server to Client Components {/*passing-props-from-server-to-client-components*/} + +As in any React app, parent components pass data to child components. As they are rendered in different environments, passing data from a Server Component to a Client Component requires extra consideration. + +Prop values passed from a Server Component to Client Component must be serializable. + +Serializable props include: +* Primitives + * [string](https://developer.mozilla.org/en-US/docs/Glossary/String) + * [number](https://developer.mozilla.org/en-US/docs/Glossary/Number) + * [bigint](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/BigInt) + * [boolean](https://developer.mozilla.org/en-US/docs/Glossary/Boolean) + * [undefined](https://developer.mozilla.org/en-US/docs/Glossary/Undefined) + * [null](https://developer.mozilla.org/en-US/docs/Glossary/Null) + * [symbol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol), only symbols registered in the global Symbol registry via [`Symbol.for`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/for) +* Iterables containing serializable values + * [String](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String) + * [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) + * [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) + * [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) + * [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) +* [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) +* [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) +* Plain [objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object), those created with [object initializers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer), with serializable properties +* Client or Server Components +* [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) + +Notably, these are not supported: +* [Functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function) that are not exported from client-marked modules or marked with [`'use server'`](/reference/react/use-server) +* [Classes](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Classes_in_JavaScript) +* Objects that are instances of any class (other than built-ins mentioned) or objects with [null-prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects) +* Symbols not registered globally, ex. `Symbol('my new symbol')` + ## Usage {/*usage*/} - -This section is a work in progress. +### Building with interactivity and state {/*building-with-interactivity-and-state*/} + + + +```js App.js +'use client'; + +import { useState } from 'react'; + +export default function Counter({initialValue = 0}) { + const [countValue, setCountValue] = useState(initialValue); + const increment = () => setCountValue(countValue + 1); + const decrement = () => setCountValue(countValue - 1); + return (<> +

Count Value: {countValue}

+ + + ); +} +``` + +
+ +As `Counter` requires both the `useState` hook and event handlers to increment or decrement the value, this component must be a Client Component and will require a `'use client'` directive at the top. + +In contrast, a component that renders UI without interaction will not need to be a Client Component. + +```js +import {getCounterValueFromFile} from 'fs-utils'; +import Counter from './Counter'; + +export default async function CounterContainer() { + const initialValue = await getCounterValueFromFile(); + return +} +``` + +For example, the parent component of the Client Component `CounterContainer` does not require `'use client'` as it is not interactive and does not use state. In addition, `CounterContainer` must be a Server Component as it reads from the local file system on the server. This is possible because Server Components, unlike Client Components, can be async functions. + +There are also components that don't use any server or client-only features and can be agnostic to where they render. `FancyText` is an example of such a component. + +```js +export default function FancyText({title, text}) { + return title + ?

{text}

+ :

{text}

+} +``` + +In this case, it is discouraged to use the `'use client'` directive as it prematurely forces all component usages of `FancyText` to be rendered on the client, which comes at a performance cost. As demonstrated in the earlier Inspirations app example, `FancyText` is used as both a Server or Client Component, depending on where it is imported and used. + +### Using client APIs {/*using-client-apis*/} + +Your React app may use client-specific APIs which are dependent on your targeted client. For the browser, some example client APIs include web storage, audio and video manipulation, and device hardware, among [others](https://developer.mozilla.org/en-US/docs/Web/API). + +In this example, the component uses [DOM APIs](https://developer.mozilla.org/en-US/docs/Glossary/DOM) to manipulate a [`canvas`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas) element. Since those APIs are only available in the browser, it must be marked as a Client Component. + +```js +'use client'; + +import {useRef, useEffect} from 'react'; + +export default function Circle() { + const ref = useRef(null); + useLayoutEffect(() => { + const canvas = ref.current; + const context = canvas.getContext('2d'); + context.beginPath(); + context.arc(100, 75, 50, 0, 2 * Math.PI); + context.stroke(); + }); + return +} +``` + +### Using React libraries {/*using-react-libraries*/} + +Often in a React app, you'll leverage third-party libraries to handle common UI patterns or logic. + +These libraries may rely on component Hooks or client APIs. In these cases, you'll need to ensure you're using these libraries in Client Components. Depending on the nature of these libraries, this may mean adding a `'use client'` near the top of your module dependency tree – marking the majority of your React app as client-rendered. + +Libraries that use any of the following React APIs must be marked as client-run: +* [createContext](/reference/react/createContext) +* [`react`](/reference/react/hooks) and [`react-dom`](/reference/react-dom/hooks) Hooks, excluding [`use`](/reference/react/use) and [`useId`](/reference/react/useId) +* [forwardRef](/reference/react/forwardRef) +* [memo](/reference/react/memo) +* [startTransition](/reference/react/startTransition) +* If they use client APIs, ex. DOM insertion or native platform views -This API can be used in any framework that supports React Server Components. You may find additional documentation from them. -* [Next.js documentation](https://nextjs.org/docs/getting-started/react-essentials) -* More coming soon -
\ No newline at end of file +[TODO]: <> (Troubleshooting - need use-cases) \ No newline at end of file From f94942863207ab816d9c339c8a8ec36c44608f45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Medrano?= Date: Tue, 31 Oct 2023 10:16:13 -0600 Subject: [PATCH 04/28] Add closing

tag (#6394) --- src/content/reference/react/Component.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/Component.md b/src/content/reference/react/Component.md index 6174cd753..f8884608b 100644 --- a/src/content/reference/react/Component.md +++ b/src/content/reference/react/Component.md @@ -632,7 +632,7 @@ class Form extends Component { return ( <> -

Hello, {this.state.name}. +

Hello, {this.state.name}.

); } From 40a88fa9a09f8809bd1c78972de99ea7698991bb Mon Sep 17 00:00:00 2001 From: DhanushShettyH <106665135+DhanushShettyH@users.noreply.github.com> Date: Fri, 3 Nov 2023 12:31:36 +0530 Subject: [PATCH 05/28] Fix typoError Mentioned in issue (#6400) --- src/components/Layout/getRouteMeta.tsx | 6 +++--- .../react-labs-what-we-have-been-working-on-march-2023.md | 2 +- src/content/learn/passing-data-deeply-with-context.md | 4 ++-- src/content/reference/react-dom/components/form.md | 2 +- src/content/reference/react/cache.md | 2 +- .../reference/react/experimental_taintUniqueValue.md | 2 +- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/Layout/getRouteMeta.tsx b/src/components/Layout/getRouteMeta.tsx index d22947847..3564dd738 100644 --- a/src/components/Layout/getRouteMeta.tsx +++ b/src/components/Layout/getRouteMeta.tsx @@ -58,13 +58,13 @@ export interface RouteMeta { order?: number; } -type TravesalContext = RouteMeta & { +type TraversalContext = RouteMeta & { currentIndex: number; }; export function getRouteMeta(cleanedPath: string, routeTree: RouteItem) { const breadcrumbs = getBreadcrumbs(cleanedPath, routeTree); - const ctx: TravesalContext = { + const ctx: TraversalContext = { currentIndex: 0, }; buildRouteMeta(cleanedPath, routeTree, ctx); @@ -79,7 +79,7 @@ export function getRouteMeta(cleanedPath: string, routeTree: RouteItem) { function buildRouteMeta( searchPath: string, currentRoute: RouteItem, - ctx: TravesalContext + ctx: TraversalContext ) { ctx.currentIndex++; diff --git a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md index a6592fd3b..5071af6ec 100644 --- a/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md +++ b/src/content/blog/2023/03/22/react-labs-what-we-have-been-working-on-march-2023.md @@ -74,7 +74,7 @@ Making plain JavaScript in React components reactive requires a compiler with a ## Offscreen Rendering {/*offscreen-rendering*/} -Offscreen rendering is an upcoming capability in React for rendering screens in the background without additional performance overhead. You can think of it as a version of the [`content-visiblity` CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility) that works not only for DOM elements but React components, too. During our research, we've discovered a variety of use cases: +Offscreen rendering is an upcoming capability in React for rendering screens in the background without additional performance overhead. You can think of it as a version of the [`content-visibility` CSS property](https://developer.mozilla.org/en-US/docs/Web/CSS/content-visibility) that works not only for DOM elements but React components, too. During our research, we've discovered a variety of use cases: - A router can prerender screens in the background so that when a user navigates to them, they're instantly available. - A tab switching component can preserve the state of hidden tabs, so the user can switch between them without losing their progress. diff --git a/src/content/learn/passing-data-deeply-with-context.md b/src/content/learn/passing-data-deeply-with-context.md index 45c5e77da..31405c0af 100644 --- a/src/content/learn/passing-data-deeply-with-context.md +++ b/src/content/learn/passing-data-deeply-with-context.md @@ -985,7 +985,7 @@ export const places = [{ }, { id: 5, name: 'Chefchaouen, Marocco', - description: 'There are a few theories on why the houses are painted blue, including that the color repells mosquitos or that it symbolizes sky and heaven.', + description: 'There are a few theories on why the houses are painted blue, including that the color repels mosquitos or that it symbolizes sky and heaven.', imageId: 'rTqKo46' }, { id: 6, @@ -1124,7 +1124,7 @@ export const places = [{ }, { id: 5, name: 'Chefchaouen, Marocco', - description: 'There are a few theories on why the houses are painted blue, including that the color repells mosquitos or that it symbolizes sky and heaven.', + description: 'There are a few theories on why the houses are painted blue, including that the color repels mosquitos or that it symbolizes sky and heaven.', imageId: 'rTqKo46' }, { id: 6, diff --git a/src/content/reference/react-dom/components/form.md b/src/content/reference/react-dom/components/form.md index 7c6023220..dfffc74f5 100644 --- a/src/content/reference/react-dom/components/form.md +++ b/src/content/reference/react-dom/components/form.md @@ -273,7 +273,7 @@ export async function deliverMessage(message) { -[//]: # 'Uncomment the next line, and delete this line after the `useOptimisitc` reference documentatino page is published' +[//]: # 'Uncomment the next line, and delete this line after the `useOptimistic` reference documentatino page is published' [//]: # 'To learn more about the `useOptimistic` Hook see the [reference documentation](/reference/react/hooks/useOptimistic).' ### Handling form submission errors {/*handling-form-submission-errors*/} diff --git a/src/content/reference/react/cache.md b/src/content/reference/react/cache.md index 65d95ab76..735560636 100644 --- a/src/content/reference/react/cache.md +++ b/src/content/reference/react/cache.md @@ -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 accessibile 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. diff --git a/src/content/reference/react/experimental_taintUniqueValue.md b/src/content/reference/react/experimental_taintUniqueValue.md index aeee7456c..e8226d92f 100644 --- a/src/content/reference/react/experimental_taintUniqueValue.md +++ b/src/content/reference/react/experimental_taintUniqueValue.md @@ -131,7 +131,7 @@ In this example, the constant `password` is tainted. Then `password` is used to Other similar ways of deriving new values from tainted values like concatenating it into a larger string, converting it to base64, or returning a substring create untained values. -Tainting only protects against simple mistakes like explictly passing secret values to the client. Mistakes in calling the `taintUniqueValue` like using a global store outside of React, without the corresponding lifetime object, can cause the tainted value to become untainted. Tainting is a layer of protection; a secure app will have multiple layers of protection, well designed APIs, and isolation patterns. +Tainting only protects against simple mistakes like explicitly passing secret values to the client. Mistakes in calling the `taintUniqueValue` like using a global store outside of React, without the corresponding lifetime object, can cause the tainted value to become untainted. Tainting is a layer of protection; a secure app will have multiple layers of protection, well designed APIs, and isolation patterns. From a8790ca810c1cebd114db35a433b90eb223dbb04 Mon Sep 17 00:00:00 2001 From: Sophie Alpert Date: Fri, 3 Nov 2023 11:00:40 -0700 Subject: [PATCH 06/28] Edits for new "use client" content (#6401) * Edits for new "use client" content * Apply suggestions from code review Co-authored-by: Luna --------- Co-authored-by: Luna --- src/content/reference/react/use-client.md | 102 +++++++++++----------- src/content/reference/react/use-server.md | 5 +- 2 files changed, 55 insertions(+), 52 deletions(-) diff --git a/src/content/reference/react/use-client.md b/src/content/reference/react/use-client.md index e0190d3fe..f4b90d288 100644 --- a/src/content/reference/react/use-client.md +++ b/src/content/reference/react/use-client.md @@ -31,20 +31,19 @@ Add `'use client'` at the top of a file to mark the module and its transitive de import { useState } from 'react'; import { formatDate } from './formatters'; -import Link from './link'; +import Button from './button'; -export default function RichTextEditor(props) { - formatDate(); +export default function RichTextEditor({ timestamp, text }) { + const date = formatDate(timestamp); + // ... + const editButton = - - ); + const [countValue, setCountValue] = useState(initialValue); + const increment = () => setCountValue(countValue + 1); + const decrement = () => setCountValue(countValue - 1); + return ( + <> +

Count Value: {countValue}

+ + + + ); } ``` @@ -311,18 +312,18 @@ As `Counter` requires both the `useState` hook and event handlers to increment o In contrast, a component that renders UI without interaction will not need to be a Client Component. ```js -import {getCounterValueFromFile} from 'fs-utils'; +import { readFile } from 'node:fs/promises'; import Counter from './Counter'; export default async function CounterContainer() { - const initialValue = await getCounterValueFromFile(); + const initialValue = await readFile('/path/to/counter_value'); return } ``` -For example, the parent component of the Client Component `CounterContainer` does not require `'use client'` as it is not interactive and does not use state. In addition, `CounterContainer` must be a Server Component as it reads from the local file system on the server. This is possible because Server Components, unlike Client Components, can be async functions. +For example, `Counter`'s parent component, `CounterContainer`, does not require `'use client'` as it is not interactive and does not use state. In addition, `CounterContainer` must be a Server Component as it reads from the local file system on the server, which is possible only in a Server Component. -There are also components that don't use any server or client-only features and can be agnostic to where they render. `FancyText` is an example of such a component. +There are also components that don't use any server or client-only features and can be agnostic to where they render. In our earlier example, `FancyText` is one such component. ```js export default function FancyText({title, text}) { @@ -332,13 +333,15 @@ export default function FancyText({title, text}) { } ``` -In this case, it is discouraged to use the `'use client'` directive as it prematurely forces all component usages of `FancyText` to be rendered on the client, which comes at a performance cost. As demonstrated in the earlier Inspirations app example, `FancyText` is used as both a Server or Client Component, depending on where it is imported and used. +In this case, we don't add the `'use client'` directive, resulting in `FancyText`'s _output_ (rather than its source code) to be sent to the browser when referenced from a Server Component. As demonstrated in the earlier Inspirations app example, `FancyText` is used as both a Server or Client Component, depending on where it is imported and used. + +But if `FancyText`'s HTML output was large relative to its source code (including dependencies), it might be more efficient to force it to always be a Client Component. Components that return a long SVG path string are one case where it may be more efficient to force a component to be a Client Component. ### Using client APIs {/*using-client-apis*/} -Your React app may use client-specific APIs which are dependent on your targeted client. For the browser, some example client APIs include web storage, audio and video manipulation, and device hardware, among [others](https://developer.mozilla.org/en-US/docs/Web/API). +Your React app may use client-specific APIs, such as the browser's APIs for web storage, audio and video manipulation, and device hardware, among [others](https://developer.mozilla.org/en-US/docs/Web/API). -In this example, the component uses [DOM APIs](https://developer.mozilla.org/en-US/docs/Glossary/DOM) to manipulate a [`canvas`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas) element. Since those APIs are only available in the browser, it must be marked as a Client Component. +In this example, the component uses [DOM APIs](https://developer.mozilla.org/en-US/docs/Glossary/DOM) to manipulate a [`canvas`](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/canvas) element. Since those APIs are only available in the browser, it must be marked as a Client Component. ```js 'use client'; @@ -350,21 +353,20 @@ export default function Circle() { useLayoutEffect(() => { const canvas = ref.current; const context = canvas.getContext('2d'); + context.reset(); context.beginPath(); context.arc(100, 75, 50, 0, 2 * Math.PI); context.stroke(); }); - return + return ; } ``` -### Using React libraries {/*using-react-libraries*/} +### Using third-party libraries {/*using-third-party-libraries*/} Often in a React app, you'll leverage third-party libraries to handle common UI patterns or logic. -These libraries may rely on component Hooks or client APIs. In these cases, you'll need to ensure you're using these libraries in Client Components. Depending on the nature of these libraries, this may mean adding a `'use client'` near the top of your module dependency tree – marking the majority of your React app as client-rendered. - -Libraries that use any of the following React APIs must be marked as client-run: +These libraries may rely on component Hooks or client APIs. Third-party components that use any of the following React APIs must run on the client: * [createContext](/reference/react/createContext) * [`react`](/reference/react/hooks) and [`react-dom`](/reference/react-dom/hooks) Hooks, excluding [`use`](/reference/react/use) and [`useId`](/reference/react/useId) * [forwardRef](/reference/react/forwardRef) @@ -372,4 +374,6 @@ Libraries that use any of the following React APIs must be marked as client-run: * [startTransition](/reference/react/startTransition) * If they use client APIs, ex. DOM insertion or native platform views +If these libraries have been updated to be compatible with React Server Components, then they will already include `'use client'` markers of their own, allowing you to use them directly from your Server Components. If a library hasn't been updated, or if a component needs props like event handlers that can only be specified on the client, you may need to add your own Client Component file in between the third-party Client Component and your Server Component where you'd like to use it. + [TODO]: <> (Troubleshooting - need use-cases) \ No newline at end of file diff --git a/src/content/reference/react/use-server.md b/src/content/reference/react/use-server.md index beaeb5f34..69f5e1044 100644 --- a/src/content/reference/react/use-server.md +++ b/src/content/reference/react/use-server.md @@ -80,8 +80,7 @@ Here are supported types for server action arguments: * [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array) * [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map) * [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) - * [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) -* [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) + * [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) and [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) * [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) * [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) instances * Plain [objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object): those created with [object initializers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer), with serializable properties @@ -92,7 +91,7 @@ Notably, these are not supported: * React elements, or [JSX](https://react.dev/learn/writing-markup-with-jsx) * Functions, including component functions or any other function that is not a server action * [Classes](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Classes_in_JavaScript) -* Objects that are instances of any class (other than built-ins mentioned) or objects with [null-prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects) +* Objects that are instances of any class (other than the built-ins mentioned) or objects with [a null prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects) * Symbols not registered globally, ex. `Symbol('my new symbol')` From 55b9e04da0c685661e84fd269ff6c4e31b83b679 Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Tue, 7 Nov 2023 07:09:49 +0900 Subject: [PATCH 07/28] Remove "canary: true" from `useTransition` in Sidebar (#6411) --- src/sidebarReference.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/sidebarReference.json b/src/sidebarReference.json index 5a6556557..315ea3e0b 100644 --- a/src/sidebarReference.json +++ b/src/sidebarReference.json @@ -82,8 +82,7 @@ }, { "title": "useTransition", - "path": "/reference/react/useTransition", - "canary": true + "path": "/reference/react/useTransition" } ] }, From 617065b8be84ee44114a6dd01af0a040c0f33fd9 Mon Sep 17 00:00:00 2001 From: Soichiro Miki Date: Tue, 7 Nov 2023 07:11:40 +0900 Subject: [PATCH 08/28] Fix style in React Reference Overview (#6410) --- src/content/reference/react/index.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/src/content/reference/react/index.md b/src/content/reference/react/index.md index 452f326d2..43394acf6 100644 --- a/src/content/reference/react/index.md +++ b/src/content/reference/react/index.md @@ -3,28 +3,32 @@ title: React Reference Overview --- -This section provides detailed reference documentation for working with React. -For an introduction to React, please visit the [Learn](/learn) section. + +This section provides detailed reference documentation for working with React. For an introduction to React, please visit the [Learn](/learn) section. + -Our The React reference documentation is broken down into functional subsections: +Our The React reference documentation is broken down into functional subsections: ## React {/*react*/} -Programmatic React features: + +Programmatic React features: + * [Hooks](/reference/react/hooks) - Use different React features from your components. * [Components](/reference/react/components) - Documents built-in components that you can use in your JSX. -* [APIs](/reference/react/apis) - APIs that are useful for defining components. +* [APIs](/reference/react/apis) - APIs that are useful for defining components. * [Directives](/reference/react/directives) - Provide instructions to bundlers compatible with React Server Components. ## React DOM {/*react-dom*/} -React-dom contains features that are only supported for web applications -(which run in the browser DOM environment). This section is broken into the following: + +React-dom contains features that are only supported for web applications (which run in the browser DOM environment). This section is broken into the following: * [Hooks](/reference/react-dom/hooks) - Hooks for web applications which run in the browser DOM environment. * [Components](/reference/react-dom/components) - React supports all of the browser built-in HTML and SVG components. * [APIs](/reference/react-dom) - The `react-dom` package contains methods supported only in web applications. -* [Client APIs](/reference/react-dom/client) - The `react-dom/client` APIs let you render React components on the client (in the browser). +* [Client APIs](/reference/react-dom/client) - The `react-dom/client` APIs let you render React components on the client (in the browser). * [Server APIs](/reference/react-dom/server) - The `react-dom/server` APIs let you render React components to HTML on the server. ## Legacy APIs {/*legacy-apis*/} -* [Legacy APIs](/reference/react/legacy) - Exported from the react package, but not recommended for use in newly written code. \ No newline at end of file + +* [Legacy APIs](/reference/react/legacy) - Exported from the `react` package, but not recommended for use in newly written code. From 8727204b04f050d1b7c065a9157fc3531552f018 Mon Sep 17 00:00:00 2001 From: Alen Ajam Date: Tue, 7 Nov 2023 00:22:48 +0100 Subject: [PATCH 09/28] fix Illustration and IllustrationBlock alt color on dark mode (#5981) --- src/components/MDX/MDXComponents.tsx | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/components/MDX/MDXComponents.tsx b/src/components/MDX/MDXComponents.tsx index 8344f9770..74ab788ba 100644 --- a/src/components/MDX/MDXComponents.tsx +++ b/src/components/MDX/MDXComponents.tsx @@ -243,7 +243,7 @@ function Illustration({ src={src} alt={alt} style={{maxHeight: 300}} - className="bg-white rounded-lg" + className="rounded-lg" /> {caption ? (
@@ -275,7 +275,12 @@ function IllustrationBlock({ const images = imageInfos.map((info, index) => (
- {info.alt} + {info.alt}
{info.caption ? (
From 42ca996138ba45775d0ba93128b3f2998d0828bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xuan=20Huang=20=28=E9=BB=84=E7=8E=84=29?= Date: Tue, 7 Nov 2023 19:56:44 +0800 Subject: [PATCH 10/28] Captailize Server Action (#6417) Summary of changes: "Server Action", like "Effect", is a React-specific notion that would be benefited from captailization to be distinguished from its genertic meaning. It seems like [Next doc](https://nextjs.org/docs/app/api-reference/functions/server-actions) has also adopted such connventions and we should probably do the same. Co-authored-by: xuan.huang --- .../reference/react-dom/components/form.md | 6 +-- .../reference/react-dom/hooks/useFormState.md | 6 +-- src/content/reference/react/use-client.md | 4 +- src/content/reference/react/use-server.md | 48 +++++++++---------- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/content/reference/react-dom/components/form.md b/src/content/reference/react-dom/components/form.md index dfffc74f5..25d1ba4e9 100644 --- a/src/content/reference/react-dom/components/form.md +++ b/src/content/reference/react-dom/components/form.md @@ -93,11 +93,11 @@ export default function Search() { ### Handle form submission with a Server Action {/*handle-form-submission-with-a-server-action*/} -Render a `` with an input and submit button. Pass a server action (a function marked with [`'use server'`](/reference/react/use-server)) to the `action` prop of form to run the function when the form is submitted. +Render a `` with an input and submit button. Pass a Server Action (a function marked with [`'use server'`](/reference/react/use-server)) to the `action` prop of form to run the function when the form is submitted. -Passing a server action to `` allow users to submit forms without JavaScript enabled or before the code has loaded. This is beneficial to users who have a slow connection, device, or have JavaScript disabled and is similar to the way forms work when a URL is passed to the `action` prop. +Passing a Server Action to `` allow users to submit forms without JavaScript enabled or before the code has loaded. This is beneficial to users who have a slow connection, device, or have JavaScript disabled and is similar to the way forms work when a URL is passed to the `action` prop. -You can use hidden form fields to provide data to the ``'s action. The server action will be called with the hidden form field data as an instance of [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData). +You can use hidden form fields to provide data to the ``'s action. The Server Action will be called with the hidden form field data as an instance of [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData). ```jsx import { updateCart } from './lib.js'; diff --git a/src/content/reference/react-dom/hooks/useFormState.md b/src/content/reference/react-dom/hooks/useFormState.md index 53c73ae38..b2808079c 100644 --- a/src/content/reference/react-dom/hooks/useFormState.md +++ b/src/content/reference/react-dom/hooks/useFormState.md @@ -51,7 +51,7 @@ function StatefulForm({}) { The form state is the value returned by the action when the form was last submitted. If the form has not yet been submitted, it is the initial state that you pass. -If used with a server action, `useFormState` allows the server's response from submitting the form to be shown even before hydration has completed. +If used with a Server Action, `useFormState` allows the server's response from submitting the form to be shown even before hydration has completed. [See more examples below.](#usage) @@ -117,7 +117,7 @@ function action(currentState, formData) { #### Display form errors {/*display-form-errors*/} -To display messages such as an error message or toast that's returned by a server action, wrap the action in a call to `useFormState`. +To display messages such as an error message or toast that's returned by a Server Action, wrap the action in a call to `useFormState`. @@ -190,7 +190,7 @@ form button { #### Display structured information after submitting a form {/*display-structured-information-after-submitting-a-form*/} -The return value from a server action can be any serializable value. For example, it could be an object that includes a boolean indicating whether the action was successful, an error message, or updated information. +The return value from a Server Action can be any serializable value. For example, it could be an object that includes a boolean indicating whether the action was successful, an error message, or updated information. diff --git a/src/content/reference/react/use-client.md b/src/content/reference/react/use-client.md index f4b90d288..be8bd0089 100644 --- a/src/content/reference/react/use-client.md +++ b/src/content/reference/react/use-client.md @@ -269,7 +269,7 @@ Serializable props include: * [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray) and [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer) * [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) * Plain [objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object): those created with [object initializers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer), with serializable properties -* Functions that are [server actions](/reference/react/use-server) +* Functions that are [Server Actions](/reference/react/use-server) * Client or Server Component elements (JSX) * [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) @@ -376,4 +376,4 @@ These libraries may rely on component Hooks or client APIs. Third-party componen If these libraries have been updated to be compatible with React Server Components, then they will already include `'use client'` markers of their own, allowing you to use them directly from your Server Components. If a library hasn't been updated, or if a component needs props like event handlers that can only be specified on the client, you may need to add your own Client Component file in between the third-party Client Component and your Server Component where you'd like to use it. -[TODO]: <> (Troubleshooting - need use-cases) \ No newline at end of file +[TODO]: <> (Troubleshooting - need use-cases) diff --git a/src/content/reference/react/use-server.md b/src/content/reference/react/use-server.md index 69f5e1044..938efa903 100644 --- a/src/content/reference/react/use-server.md +++ b/src/content/reference/react/use-server.md @@ -25,7 +25,7 @@ canary: true ### `'use server'` {/*use-server*/} -Add `'use server'` at the top of an async function body to mark the function as callable by the client. We call these functions _server actions_. +Add `'use server'` at the top of an async function body to mark the function as callable by the client. We call these functions _Server Actions_. ```js {2} async function addToCart(data) { @@ -34,28 +34,28 @@ async function addToCart(data) { } ``` -When calling a server action on the client, it will make a network request to the server that includes a serialized copy of any arguments passed. If the server action returns a value, that value will be serialized and returned to the client. +When calling a Server Action on the client, it will make a network request to the server that includes a serialized copy of any arguments passed. If the Server Action returns a value, that value will be serialized and returned to the client. -Instead of individually marking functions with `'use server'`, you can add the directive to the top of a file to mark all exports within that file as server actions that can be used anywhere, including imported in client code. +Instead of individually marking functions with `'use server'`, you can add the directive to the top of a file to mark all exports within that file as Server Actions that can be used anywhere, including imported in client code. #### Caveats {/*caveats*/} * `'use server'` must be at the very beginning of their function or module; above any other code including imports (comments above directives are OK). They must be written with single or double quotes, not backticks. -* `'use server'` can only be used in server-side files. The resulting server actions can be passed to Client Components through props. See supported [types for serialization](#serializable-parameters-and-return-values). -* To import a server action from [client code](/reference/react/use-client), the directive must be used on a module level. +* `'use server'` can only be used in server-side files. The resulting Server Actions can be passed to Client Components through props. See supported [types for serialization](#serializable-parameters-and-return-values). +* To import a Server Action from [client code](/reference/react/use-client), the directive must be used on a module level. * Because the underlying network calls are always asynchronous, `'use server'` can only be used on async functions. -* Always treat arguments to server actions as untrusted input and authorize any mutations. See [security considerations](#security). -* Server actions should be called in a [transition](/reference/react/useTransition). Server actions passed to [``](/reference/react-dom/components/form#props) or [`formAction`](/reference/react-dom/components/input#props) will automatically be called in a transition. -* Server actions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing server actions typically process one action at a time and do not have a way to cache the return value. +* Always treat arguments to Server Actions as untrusted input and authorize any mutations. See [security considerations](#security). +* Server Actions should be called in a [transition](/reference/react/useTransition). Server Actions passed to [``](/reference/react-dom/components/form#props) or [`formAction`](/reference/react-dom/components/input#props) will automatically be called in a transition. +* Server Actions are designed for mutations that update server-side state; they are not recommended for data fetching. Accordingly, frameworks implementing Server Actions typically process one action at a time and do not have a way to cache the return value. ### Security considerations {/*security*/} -Arguments to server actions are fully client-controlled. For security, always treat them as untrusted input, and make sure to validate and escape arguments as appropriate. +Arguments to Server Actions are fully client-controlled. For security, always treat them as untrusted input, and make sure to validate and escape arguments as appropriate. -In any server action, make sure to validate that the logged-in user is allowed to perform that action. +In any Server Action, make sure to validate that the logged-in user is allowed to perform that action. -To prevent sending sensitive data from a server action, there are experimental taint APIs to prevent unique values and objects from being passed to client code. +To prevent sending sensitive data from a Server Action, there are experimental taint APIs to prevent unique values and objects from being passed to client code. See [experimental_taintUniqueValue](/reference/react/experimental_taintUniqueValue) and [experimental_taintObjectReference](/reference/react/experimental_taintObjectReference). @@ -63,9 +63,9 @@ See [experimental_taintUniqueValue](/reference/react/experimental_taintUniqueVal ### Serializable arguments and return values {/*serializable-parameters-and-return-values*/} -As client code calls the server action over the network, any arguments passed will need to be serializable. +As client code calls the Server Action over the network, any arguments passed will need to be serializable. -Here are supported types for server action arguments: +Here are supported types for Server Action arguments: * Primitives * [string](https://developer.mozilla.org/en-US/docs/Glossary/String) @@ -84,12 +84,12 @@ Here are supported types for server action arguments: * [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) * [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) instances * Plain [objects](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object): those created with [object initializers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer), with serializable properties -* Functions that are server actions +* Functions that are Server Actions * [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) Notably, these are not supported: * React elements, or [JSX](https://react.dev/learn/writing-markup-with-jsx) -* Functions, including component functions or any other function that is not a server action +* Functions, including component functions or any other function that is not a Server Action * [Classes](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Classes_in_JavaScript) * Objects that are instances of any class (other than the built-ins mentioned) or objects with [a null prototype](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object#null-prototype_objects) * Symbols not registered globally, ex. `Symbol('my new symbol')` @@ -100,9 +100,9 @@ Supported serializable return values are the same as [serializable props](/refer ## Usage {/*usage*/} -### Server actions in forms {/*server-actions-in-forms*/} +### Server Actions in forms {/*server-actions-in-forms*/} -The most common use case of server actions will be calling server functions that mutate data. On the browser, the [HTML form element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) is the traditional approach for a user to submit a mutation. With React Server Components, React introduces first-class support for server actions in [forms](/reference/react-dom/components/form). +The most common use case of Server Actions will be calling server functions that mutate data. On the browser, the [HTML form element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form) is the traditional approach for a user to submit a mutation. With React Server Components, React introduces first-class support for Server Actions in [forms](/reference/react-dom/components/form). Here is a form that allows a user to request a username. @@ -123,15 +123,15 @@ export default App() { } ``` -In this example `requestUsername` is a server action passed to a ``. When a user submits this form, there is a network request to the server function `requestUsername`. When calling a server action in a form, React will supply the form's [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) as the first argument to the server action. +In this example `requestUsername` is a Server Action passed to a ``. When a user submits this form, there is a network request to the server function `requestUsername`. When calling a Server Action in a form, React will supply the form's [FormData](https://developer.mozilla.org/en-US/docs/Web/API/FormData) as the first argument to the Server Action. -By passing a server action to the form `action`, React can [progressively enhance](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement) the form. This means that forms can be submitted before the JavaScript bundle is loaded. +By passing a Server Action to the form `action`, React can [progressively enhance](https://developer.mozilla.org/en-US/docs/Glossary/Progressive_Enhancement) the form. This means that forms can be submitted before the JavaScript bundle is loaded. #### Handling return values in forms {/*handling-return-values*/} In the username request form, there might be the chance that a username is not available. `requestUsername` should tell us if it fails or not. -To update the UI based on the result of a server action while supporting progressive enhancement, use [`useFormState`](/reference/react-dom/hooks/useFormState). +To update the UI based on the result of a Server Action while supporting progressive enhancement, use [`useFormState`](/reference/react-dom/hooks/useFormState). ```js // requestUsername.js @@ -171,11 +171,11 @@ function UsernameForm() { Note that like most Hooks, `useFormState` can only be called in [client code](/reference/react/use-client). -### Calling a server action outside of `` {/*calling-a-server-action-outside-of-form*/} +### Calling a Server Action outside of `` {/*calling-a-server-action-outside-of-form*/} -Server actions are exposed server endpoints and can be called anywhere in client code. +Server Actions are exposed server endpoints and can be called anywhere in client code. -When using a server action outside of a [form](/reference/react-dom/components/form), call the server action in a [transition](/reference/react/useTransition), which allows you to display a loading indicator, show [optimistic state updates](/reference/react/useOptimistic), and handle unexpected errors. Forms will automatically wrap server actions in transitions. +When using a Server Action outside of a [form](/reference/react-dom/components/form), call the Server Action in a [transition](/reference/react/useTransition), which allows you to display a loading indicator, show [optimistic state updates](/reference/react/useOptimistic), and handle unexpected errors. Forms will automatically wrap Server Actions in transitions. ```js {9-12} import incrementLike from './actions'; @@ -212,4 +212,4 @@ export default async incrementLike() { } ``` -To read a server action return value, you'll need to `await` the promise returned. \ No newline at end of file +To read a Server Action return value, you'll need to `await` the promise returned. From 292e55de89ed813209c27a34291ea8e06bd306e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xuan=20Huang=20=28=E9=BB=84=E7=8E=84=29?= Date: Tue, 7 Nov 2023 20:32:52 +0800 Subject: [PATCH 11/28] Capitalize Client/Server Component (#6418) Summary of changes: following Co-authored-by: xuan.huang --- .../06/15/react-labs-what-we-have-been-working-on-june-2022.md | 2 +- src/content/reference/react/use.md | 2 +- src/content/reference/react/useId.md | 3 +-- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md index 938b75c4b..df864db10 100644 --- a/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md +++ b/src/content/blog/2022/06/15/react-labs-what-we-have-been-working-on-june-2022.md @@ -28,7 +28,7 @@ We’re working together with Vercel and Shopify to unify bundler support for sh ## Asset Loading {/*asset-loading*/} -Currently, assets like scripts, external styles, fonts, and images are typically preloaded and loaded using external systems. This can make it tricky to coordinate across new environments like streaming, server components, and more. +Currently, assets like scripts, external styles, fonts, and images are typically preloaded and loaded using external systems. This can make it tricky to coordinate across new environments like streaming, Server Components, and more. We’re looking at adding APIs to preload and load deduplicated external assets through React APIs that work in all React environments. We’re also looking at having these support Suspense so you can have images, CSS, and fonts that block display until they’re loaded but don’t block streaming and concurrent rendering. This can help avoid [“popcorning“](https://twitter.com/sebmarkbage/status/1516852731251724293) as the visuals pop and layout shifts. diff --git a/src/content/reference/react/use.md b/src/content/reference/react/use.md index 8e1a8f213..b726e67db 100644 --- a/src/content/reference/react/use.md +++ b/src/content/reference/react/use.md @@ -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` 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. ```js export default function App() { diff --git a/src/content/reference/react/useId.md b/src/content/reference/react/useId.md index 4ea029f27..96a5e25a2 100644 --- a/src/content/reference/react/useId.md +++ b/src/content/reference/react/useId.md @@ -179,7 +179,7 @@ You might be wondering why `useId` is better than incrementing a global variable The primary benefit of `useId` is that React ensures that it works with [server rendering.](/reference/react-dom/server) During server rendering, your components generate HTML output. Later, on the client, [hydration](/reference/react-dom/client/hydrateRoot) attaches your event handlers to the generated HTML. For hydration to work, the client output must match the server HTML. -This is very difficult to guarantee with an incrementing counter because the order in which the client components are hydrated may not match the order in which the server HTML was emitted. By calling `useId`, you ensure that hydration will work, and the output will match between the server and the client. +This is very difficult to guarantee with an incrementing counter because the order in which the Client Components are hydrated may not match the order in which the server HTML was emitted. By calling `useId`, you ensure that hydration will work, and the output will match between the server and the client. Inside React, `useId` is generated from the "parent path" of the calling component. This is why, if the client and the server tree are the same, the "parent path" will match up regardless of rendering order. @@ -302,4 +302,3 @@ input { margin: 5px; } ``` - From c5a2e15d58eeaa8f4952edc2d00cedb158e4b037 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xuan=20Huang=20=28=E9=BB=84=E7=8E=84=29?= Date: Tue, 7 Nov 2023 20:50:57 +0800 Subject: [PATCH 12/28] Capitalize Client in "client modules" (#6419) Summary of changes: See Co-authored-by: xuan.huang --- src/content/reference/react/use-client.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/content/reference/react/use-client.md b/src/content/reference/react/use-client.md index be8bd0089..dedd2480a 100644 --- a/src/content/reference/react/use-client.md +++ b/src/content/reference/react/use-client.md @@ -51,14 +51,14 @@ As dependencies of `RichTextEditor`, `formatDate` and `Button` will also be eval * When a `'use client'` module is imported from another client-rendered module, the directive has no effect. * When a component module contains a `'use client'` directive, any usage of that component is guaranteed to be a Client Component. However, a component can still be evaluated on the client even if it does not have a `'use client'` directive. * A component usage is considered a Client Component if it is defined in module with `'use client'` directive or when it is a transitive dependency of a module that contains a `'use client'` directive. Otherwise, it is a Server Component. -* Code that is marked for client evaluation is not limited to components. All code that is a part of the client module sub-tree is sent to and run by the client. +* Code that is marked for client evaluation is not limited to components. All code that is a part of the Client module sub-tree is sent to and run by the client. * When a server evaluated module imports values from a `'use client'` module, the values must either be a React component or [supported serializable prop values](#passing-props-from-server-to-client-components) to be passed to a Client Component. Any other use case will throw an exception. ### How `'use client'` marks client code {/*how-use-client-marks-client-code*/} In a React app, components are often split into separate files, or [modules](/learn/importing-and-exporting-components#exporting-and-importing-a-component). -For apps that use React Server Components, the app is server-rendered by default. `'use client'` introduces a server-client boundary in the [module dependency tree](/learn/understanding-your-ui-as-a-tree#the-module-dependency-tree), effectively creating a subtree of client modules. +For apps that use React Server Components, the app is server-rendered by default. `'use client'` introduces a server-client boundary in the [module dependency tree](/learn/understanding-your-ui-as-a-tree#the-module-dependency-tree), effectively creating a subtree of Client modules. To better illustrate this, consider the following React Server Components app. @@ -145,7 +145,7 @@ export default [ -In the module dependency tree of this example app, the `'use client'` directive in `InspirationGenerator.js` marks that module and all of its transitive dependencies as client modules. The subtree starting at `InspirationGenerator.js` is now marked as client modules. +In the module dependency tree of this example app, the `'use client'` directive in `InspirationGenerator.js` marks that module and all of its transitive dependencies as Client modules. The subtree starting at `InspirationGenerator.js` is now marked as Client modules. `'use client'` segments the module dependency tree of the React Server Components app, marking `InspirationGenerator.js` and all of its dependencies as client-rendered. @@ -237,7 +237,7 @@ With `'use client'`, you can determine when components are Client Components. As For simplicity, we talk about Server Components, but the same principles apply to all code in your app that is server run. #### Advantages of Server Components {/*advantages*/} -* Server Components can reduce the amount of code sent and run by the client. Only client modules are bundled and evaluated by the client. +* Server Components can reduce the amount of code sent and run by the client. Only Client modules are bundled and evaluated by the client. * Server Components benefit from running on the server. They can access the local filesystem and may experience low latency for data fetches and network requests. #### Limitations of Server Components {/*limitations*/} From 721479b34668cb1bdfe2e312a86c04f08cd5d659 Mon Sep 17 00:00:00 2001 From: Kathryn Middleton Date: Tue, 7 Nov 2023 09:36:55 -0500 Subject: [PATCH 13/28] Check for value before passing to gtag (#6415) --- src/components/Layout/Feedback.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Layout/Feedback.tsx b/src/components/Layout/Feedback.tsx index 86fc91350..b36112c47 100644 --- a/src/components/Layout/Feedback.tsx +++ b/src/components/Layout/Feedback.tsx @@ -45,13 +45,14 @@ const thumbsDownIcon = ( ); function sendGAEvent(isPositive: boolean) { + const value = isPositive ? 1 : 0; // Fragile. Don't change unless you've tested the network payload // and verified that the right events actually show up in GA. // @ts-ignore gtag('event', 'feedback', { event_category: 'button', event_label: window.location.pathname, - value: isPositive ? 1 : 0, + value, }); } From eeb0979c3c41870530b08e7d46780655ccfc8580 Mon Sep 17 00:00:00 2001 From: Kathryn Middleton Date: Wed, 8 Nov 2023 11:40:02 -0500 Subject: [PATCH 14/28] Update event label and value name (#6421) --- src/components/Layout/Feedback.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/Layout/Feedback.tsx b/src/components/Layout/Feedback.tsx index b36112c47..8639ce12c 100644 --- a/src/components/Layout/Feedback.tsx +++ b/src/components/Layout/Feedback.tsx @@ -45,14 +45,15 @@ const thumbsDownIcon = ( ); function sendGAEvent(isPositive: boolean) { + const category = isPositive ? 'like_button' : 'dislike_button'; const value = isPositive ? 1 : 0; // Fragile. Don't change unless you've tested the network payload // and verified that the right events actually show up in GA. // @ts-ignore gtag('event', 'feedback', { - event_category: 'button', + event_category: category, event_label: window.location.pathname, - value, + event_value: value, }); } From 49ebed1b5bc753b9584ea137943ab22985f3bfe3 Mon Sep 17 00:00:00 2001 From: Kathryn Middleton Date: Wed, 8 Nov 2023 13:08:58 -0500 Subject: [PATCH 15/28] Fix useOptimistic demo bug (#6422) --- src/content/reference/react/useOptimistic.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/useOptimistic.md b/src/content/reference/react/useOptimistic.md index d0511b1a9..47593a0ae 100644 --- a/src/content/reference/react/useOptimistic.md +++ b/src/content/reference/react/useOptimistic.md @@ -116,7 +116,7 @@ export default function App() { ]); async function sendMessage(formData) { const sentMessage = await deliverMessage(formData.get("message")); - setMessages([...messages, { text: sentMessage }]); + setMessages((messages) => [...messages, { text: sentMessage }]); } return ; } From 44f442d5b201c633619c1c9a5fec784891c696ae Mon Sep 17 00:00:00 2001 From: Luna Date: Wed, 8 Nov 2023 19:55:40 -0400 Subject: [PATCH 16/28] Add space for canary title (#6416) Co-authored-by: Luna Wei --- src/components/Layout/Sidebar/SidebarLink.tsx | 2 +- src/components/PageHeading.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/Layout/Sidebar/SidebarLink.tsx b/src/components/Layout/Sidebar/SidebarLink.tsx index 180ded867..8a71d9e6e 100644 --- a/src/components/Layout/Sidebar/SidebarLink.tsx +++ b/src/components/Layout/Sidebar/SidebarLink.tsx @@ -77,7 +77,7 @@ export function SidebarLink({ {title}{' '} {canary && ( )} diff --git a/src/components/PageHeading.tsx b/src/components/PageHeading.tsx index 076a38be9..659295d0a 100644 --- a/src/components/PageHeading.tsx +++ b/src/components/PageHeading.tsx @@ -34,7 +34,7 @@ function PageHeading({ {title} {canary && ( )} From fcd00068bd1bdd4eb37e3e0ab0488a9d093670bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Xuan=20Huang=20=28=E9=BB=84=E7=8E=84=29?= Date: Fri, 10 Nov 2023 21:57:45 +0800 Subject: [PATCH 17/28] Capitalize word "Hook" (#6424) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary of changes: See . There is one exception though. The error message “Rendered fewer hooks than expected” from React is indeed "hooks" so I kept as-is. Shall we change the error message from React? Co-authored-by: xuan.huang --- .../blog/2022/03/08/react-18-upgrade-guide.md | 4 ++-- src/content/blog/2022/03/29/react-v18.md | 11 +++++----- ...-what-we-have-been-working-on-june-2022.md | 2 +- ...what-we-have-been-working-on-march-2023.md | 2 +- src/content/learn/typescript.md | 20 +++++++++---------- src/content/reference/react/use-client.md | 2 +- 6 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/content/blog/2022/03/08/react-18-upgrade-guide.md b/src/content/blog/2022/03/08/react-18-upgrade-guide.md index 29ba0b71d..66da896ec 100644 --- a/src/content/blog/2022/03/08/react-18-upgrade-guide.md +++ b/src/content/blog/2022/03/08/react-18-upgrade-guide.md @@ -224,8 +224,8 @@ For more information, see the [Automatic batching deep dive](https://github.com/ In the React 18 Working Group we worked with library maintainers to create new APIs needed to support concurrent rendering for use cases specific to their use case in areas like styles, and external stores. To support React 18, some libraries may need to switch to one of the following APIs: -* `useSyncExternalStore` is a new hook that allows external stores to support concurrent reads by forcing updates to the store to be synchronous. This new API is recommended for any library that integrates with state external to React. For more information, see the [useSyncExternalStore overview post](https://github.com/reactwg/react-18/discussions/70) and [useSyncExternalStore API details](https://github.com/reactwg/react-18/discussions/86). -* `useInsertionEffect` is a new hook that allows CSS-in-JS libraries to address performance issues of injecting styles in render. Unless you've already built a CSS-in-JS library we don't expect you to ever use this. This hook will run after the DOM is mutated, but before layout effects read the new layout. This solves an issue that already exists in React 17 and below, but is even more important in React 18 because React yields to the browser during concurrent rendering, giving it a chance to recalculate layout. For more information, see the [Library Upgrade Guide for `