Skip to content

Commit a8790ca

Browse files
Edits for new "use client" content (#6401)
* Edits for new "use client" content * Apply suggestions from code review Co-authored-by: Luna <lunaleaps@gmail.com> --------- Co-authored-by: Luna <lunaleaps@gmail.com>
1 parent 40a88fa commit a8790ca

File tree

2 files changed

+55
-52
lines changed

2 files changed

+55
-52
lines changed

src/content/reference/react/use-client.md

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -31,20 +31,19 @@ Add `'use client'` at the top of a file to mark the module and its transitive de
3131

3232
import { useState } from 'react';
3333
import { formatDate } from './formatters';
34-
import Link from './link';
34+
import Button from './button';
3535

36-
export default function RichTextEditor(props) {
37-
formatDate();
36+
export default function RichTextEditor({ timestamp, text }) {
37+
const date = formatDate(timestamp);
38+
// ...
39+
const editButton = <Button />;
3840
// ...
39-
return
40-
<Link />
41-
// ...
4241
}
4342
```
4443

4544
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.
4645

47-
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.
46+
As dependencies of `RichTextEditor`, `formatDate` and `Button` will also be evaluated on the client regardless of whether their modules contain a `'use client'` directive. Note that a single module may be evaluated on the server when imported from server code and on the client when imported from client code.
4847

4948
#### Caveats {/*caveats*/}
5049

@@ -59,9 +58,9 @@ As a dependency of `RichTextEditor`, `formatDate` and `Link` will also be evalua
5958

6059
In a React app, components are often split into separate files, or [modules](/learn/importing-and-exporting-components#exporting-and-importing-a-component).
6160

62-
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.
61+
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.
6362

64-
To better illustrate this, consider the following React Server Component app and its module dependency and render tree.
63+
To better illustrate this, consider the following React Server Components app.
6564

6665
<Sandpack>
6766

@@ -146,12 +145,12 @@ export default [
146145

147146
</Sandpack>
148147

148+
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.
149+
149150
<Diagram name="use_client_module_dependency" height={250} width={545} alt="A tree graph with the top node representing the module 'App.js'. 'App.js' has three children: 'Copyright.js', 'FancyText.js', and 'InspirationGenerator.js'. 'InspirationGenerator.js' has two children: 'FancyText.js' and 'inspirations.js'. The nodes under and including 'InspirationGenerator.js' have a yellow background color to signify that this sub-graph is client-rendered due to the 'use client' directive in 'InspirationGenerator.js'.">
150-
`'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.
151+
`'use client'` segments the module dependency tree of the React Server Components app, marking `InspirationGenerator.js` and all of its dependencies as client-rendered.
151152
</Diagram>
152153

153-
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.
154-
155154
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.
156155

157156
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.
@@ -179,7 +178,7 @@ First, let's clarify that the term "component" is not very precise. Here are jus
179178
```js
180179
// This is a definition of a component
181180
function MyComponent() {
182-
return <p>My Component</p>
181+
return <p>My Component</p>
183182
}
184183
```
185184

@@ -188,8 +187,8 @@ function MyComponent() {
188187
import MyComponent from './MyComponent';
189188

190189
function App() {
191-
// This is a usage of a component
192-
return <MyComponent />;
190+
// This is a usage of a component
191+
return <MyComponent />;
193192
}
194193
```
195194

@@ -215,39 +214,39 @@ This means that the component definition for `FancyText` will both be evaluated
215214

216215
#### Why is `Copyright` a Server Component? {/*why-is-copyright-a-server-component*/}
217216

218-
As a child of `InspirationGenerator`, a Client Component, why is `Copyright` a Server Component?
217+
Because `Copyright` is rendered as a child of the Client Component `InspirationGenerator`, you might be surprised that it is a Server Component.
219218

220-
To clarify, `'use client'` defines the boundary between server and client code on the _module dependency tree_, not the render tree.
219+
Recall that `'use client'` defines the boundary between server and client code on the _module dependency tree_, not the render tree.
221220

222221
<Diagram name="use_client_module_dependency" height={200} width={500} alt="A tree graph with the top node representing the module 'App.js'. 'App.js' has three children: 'Copyright.js', 'FancyText.js', and 'InspirationGenerator.js'. 'InspirationGenerator.js' has two children: 'FancyText.js' and 'inspirations.js'. The nodes under and including 'InspirationGenerator.js' have a yellow background color to signify that this sub-graph is client-rendered due to the 'use client' directive in 'InspirationGenerator.js'.">
223222
`'use client'` defines the boundary between server and client code on the module dependency tree.
224223
</Diagram>
225224

226225
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.
227226

228-
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`.
227+
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`. In fact, the `Copyright` component is fully executed before `InspirationGenerator` starts rendering.
229228

230229
The takeaway is that a parent-child render relationship between components does not guarantee the same render environment.
231230

232231
</DeepDive>
233232

234233
### When to use `'use client'` {/*when-to-use-use-client*/}
235234

236-
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.
235+
With `'use client'`, you can determine when components are 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.
237236

238237
For simplicity, we talk about Server Components, but the same principles apply to all code in your app that is server run.
239238

240-
#### Advantages {/*advantages*/}
239+
#### Advantages of Server Components {/*advantages*/}
241240
* Server Components can reduce the amount of code sent and run by the client. Only client modules are bundled and evaluated by the client.
242241
* 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.
243242

244-
#### Limitations {/*limitations*/}
243+
#### Limitations of Server Components {/*limitations*/}
245244
* Server Components cannot support interaction as event handlers must be registered and triggered by a client.
246-
* The browser, as an example client, is responsible for delegating UI clicks to the appropriate `onClick` handler.
245+
* For example, event handlers like `onClick` can only be defined in Client Components.
247246
* Server Components cannot use most Hooks.
248-
* 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.
247+
* When Server Components are rendered, their output is essentially a list of components for the client to render. Server Components do not persist in memory after render and cannot have their own state.
249248

250-
### Passing props from Server to Client Components {/*passing-props-from-server-to-client-components*/}
249+
### Serializable types returned by Server Components {/*serializable-types*/}
251250

252251
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.
253252

@@ -267,17 +266,17 @@ Serializable props include:
267266
* [Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array)
268267
* [Map](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map)
269268
* [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set)
270-
* [TypedArray](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray)
271-
* [ArrayBuffer](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer)
269+
* [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)
272270
* [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date)
273-
* 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
274-
* Client or Server Components
271+
* 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
272+
* Functions that are [server actions](/reference/react/use-server)
273+
* Client or Server Component elements (JSX)
275274
* [Promises](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
276275

277276
Notably, these are not supported:
278277
* [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)
279278
* [Classes](https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Classes_in_JavaScript)
280-
* 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)
279+
* 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)
281280
* Symbols not registered globally, ex. `Symbol('my new symbol')`
282281

283282

@@ -293,14 +292,16 @@ Notably, these are not supported:
293292
import { useState } from 'react';
294293

295294
export default function Counter({initialValue = 0}) {
296-
const [countValue, setCountValue] = useState(initialValue);
297-
const increment = () => setCountValue(countValue + 1);
298-
const decrement = () => setCountValue(countValue - 1);
299-
return (<>
300-
<h2>Count Value: {countValue}</h2>
301-
<button onClick={increment}>+1</button>
302-
<button onClick={decrement}>-1</button>
303-
</>);
295+
const [countValue, setCountValue] = useState(initialValue);
296+
const increment = () => setCountValue(countValue + 1);
297+
const decrement = () => setCountValue(countValue - 1);
298+
return (
299+
<>
300+
<h2>Count Value: {countValue}</h2>
301+
<button onClick={increment}>+1</button>
302+
<button onClick={decrement}>-1</button>
303+
</>
304+
);
304305
}
305306
```
306307

@@ -311,18 +312,18 @@ As `Counter` requires both the `useState` hook and event handlers to increment o
311312
In contrast, a component that renders UI without interaction will not need to be a Client Component.
312313

313314
```js
314-
import {getCounterValueFromFile} from 'fs-utils';
315+
import { readFile } from 'node:fs/promises';
315316
import Counter from './Counter';
316317

317318
export default async function CounterContainer() {
318-
const initialValue = await getCounterValueFromFile();
319+
const initialValue = await readFile('/path/to/counter_value');
319320
return <Counter initialValue={initialValue} />
320321
}
321322
```
322323

323-
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.
324+
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.
324325

325-
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.
326+
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.
326327

327328
```js
328329
export default function FancyText({title, text}) {
@@ -332,13 +333,15 @@ export default function FancyText({title, text}) {
332333
}
333334
```
334335

335-
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.
336+
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.
337+
338+
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.
336339

337340
### Using client APIs {/*using-client-apis*/}
338341

339-
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).
342+
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).
340343

341-
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.
344+
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.
342345

343346
```js
344347
'use client';
@@ -350,26 +353,27 @@ export default function Circle() {
350353
useLayoutEffect(() => {
351354
const canvas = ref.current;
352355
const context = canvas.getContext('2d');
356+
context.reset();
353357
context.beginPath();
354358
context.arc(100, 75, 50, 0, 2 * Math.PI);
355359
context.stroke();
356360
});
357-
return <canvas ref={ref} />
361+
return <canvas ref={ref} />;
358362
}
359363
```
360364

361-
### Using React libraries {/*using-react-libraries*/}
365+
### Using third-party libraries {/*using-third-party-libraries*/}
362366

363367
Often in a React app, you'll leverage third-party libraries to handle common UI patterns or logic.
364368

365-
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.
366-
367-
Libraries that use any of the following React APIs must be marked as client-run:
369+
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:
368370
* [createContext](/reference/react/createContext)
369371
* [`react`](/reference/react/hooks) and [`react-dom`](/reference/react-dom/hooks) Hooks, excluding [`use`](/reference/react/use) and [`useId`](/reference/react/useId)
370372
* [forwardRef](/reference/react/forwardRef)
371373
* [memo](/reference/react/memo)
372374
* [startTransition](/reference/react/startTransition)
373375
* If they use client APIs, ex. DOM insertion or native platform views
374376

377+
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.
378+
375379
[TODO]: <> (Troubleshooting - need use-cases)

0 commit comments

Comments
 (0)