You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0541585
Browse filesBrowse the repository at this point in the historyBrowse files
@@ -38,92 +38,52 @@ import { Activity } from 'react';
38
38
39
39
An Activity boundary supports two modes:
40
40
41
-
- In `visible` mode, React renders the children and runs the setup functions for
42
-
their `useEffect` and `useLayoutEffect` calls.
43
-
- In `hidden` mode, React hides the children and runs the cleanup functions for
44
-
their `useEffect` and `useLayoutEffect` calls. React preserves their state and
45
-
renders updates at a lower priority than updates to visible content.
41
+
- In `visible` mode, React renders the children, attaches their refs, and runs the setup functions for their `useEffect` and `useLayoutEffect` calls.
42
+
- In `hidden` mode, React hides the children, detaches their refs, and runs the cleanup functions for their `useEffect` and `useLayoutEffect` calls. React preserves their state and renders updates at a lower priority than updates to visible content.
46
43
47
-
When a hidden Activity boundary becomes visible, React reveals its children with
48
-
their previous state and runs their Effect setup functions again.
44
+
When a hidden Activity boundary becomes visible, React reveals its children with their previous state and runs their Effect setup functions again.
49
45
50
-
In React DOM, hiding an Activity boundary applies `display: none` to the nearest
51
-
DOM elements inside the boundary. React preserves those elements while the
52
-
boundary remains mounted.
46
+
In React DOM, hiding an Activity boundary applies `display: none` to the nearest DOM elements inside the boundary. React preserves those elements while the boundary remains mounted.
47
+
48
+
Insertion Effects created with [`useInsertionEffect`](/reference/react/useInsertionEffect) remain connected while an Activity boundary is hidden because styles may still be needed by the preserved DOM.
53
49
54
50
#### Props {/*props*/}
55
51
56
-
*`children`: The UI rendered by the Activity boundary. `children` can be any
***optional**`mode`: Either `'visible'` or `'hidden'`. Defaults to `'visible'`.
59
-
See [Modes](#modes) for the behavior of each value.
60
-
***optional**`name`: A string that identifies the Activity boundary in React
61
-
Developer Tools.
52
+
*`children`: The UI rendered by the Activity boundary. `children` can be any [React node](/reference/react/isValidElement#react-elements-vs-react-nodes).
53
+
***optional**`mode`: Either `'visible'` or `'hidden'`. Defaults to `'visible'`. See [Modes](#modes) for the behavior of each value.
54
+
***optional**`name`: A string that identifies the Activity boundary in React Developer Tools.
62
55
63
56
#### Caveats {/*caveats*/}
64
57
65
-
- Hiding an Activity boundary retains its state and DOM nodes, so React does not
66
-
reclaim all memory associated with the hidden subtree.
67
-
- Browser behavior associated with preserved DOM nodes can continue while the
68
-
boundary is hidden. For example, audio and video can continue playing. Use an
69
-
Effect cleanup function to stop this behavior.
70
-
[See an example below.](#my-hidden-components-have-unwanted-side-effects)
71
-
- React runs cleanup functions for Effects created with `useEffect` and
72
-
`useLayoutEffect` when an Activity boundary becomes hidden. Insertion Effects
changing it from hidden to visible as part of an update started with
87
-
[`startTransition`](/reference/react/startTransition) activates the `enter`
88
-
animation. Changing it from visible to hidden as part of that update activates
89
-
the `exit` animation.
58
+
- Browser behavior associated with preserved DOM nodes can continue while the boundary is hidden. For example, audio and video can continue playing. Use an Effect cleanup function to stop this behavior. [See an example below.](#my-hidden-components-have-unwanted-side-effects)
59
+
- React omits text-only output while an Activity boundary is hidden because a text node cannot receive `display: none`. The text appears when the boundary becomes visible.
60
+
- If an Activity boundary is inside [`<ViewTransition>`](/reference/react/ViewTransition), changing it from hidden to visible as part of an update started with [`startTransition`](/reference/react/startTransition) activates the `enter` animation. Changing it from visible to hidden as part of that update activates the `exit` animation.
90
61
91
62
---
92
63
93
64
## Usage {/*usage*/}
94
65
95
-
Activity is useful when part of the UI may become hidden and visible again. Unlike
96
-
conditional rendering, hiding an Activity boundary preserves both React state and
97
-
the DOM state of its children. Unlike hiding content only with CSS, Activity also
98
-
cleans up the children's Effects and deprioritizes their updates while they are
99
-
hidden.
66
+
Activity is useful when part of the UI may become hidden and visible again. Unlike conditional rendering, hiding an Activity boundary preserves both React state and the DOM state of its children. Unlike hiding content only with CSS, Activity also cleans up the children's Effects and deprioritizes their updates while they are hidden.
100
67
101
-
Use an Activity boundary when preserving that work is valuable—for example, for a
102
-
tab the user is likely to revisit or a panel that can prepare data in the
103
-
background. If the content is unlikely to become visible again, conditionally
104
-
rendering it may be preferable because unmounting allows React and the browser to
105
-
release its resources.
68
+
Use an Activity boundary when preserving that work is valuable—for example, for a tab the user is likely to revisit or a panel that can prepare data in the background. A hidden boundary retains its state and DOM nodes, so it continues using memory. If the content is unlikely to become visible again, conditionally rendering it may be preferable because unmounting allows React and the browser to release its resources.
106
69
107
70
### Preserving state while content is hidden {/*restoring-the-state-of-hidden-components*/}
108
71
109
-
When this condition becomes false, React removes `<Sidebar>` from the tree and
110
-
discards its state:
72
+
When this condition becomes false, React removes `<Sidebar>` from the tree and discards its state:
111
73
112
74
```js
113
75
{isShowingSidebar &&<Sidebar />}
114
76
```
115
77
116
-
Render the component inside an Activity boundary to preserve its state while it is
117
-
hidden:
78
+
Render the component inside an Activity boundary to preserve its state while it is hidden:
In this example, expand the sidebar, hide it, and show it again. The expanded state
126
-
is preserved.
86
+
In this example, expand the sidebar, hide it, and show it again. The expanded state is preserved.
127
87
128
88
<Sandpack>
129
89
@@ -208,21 +168,15 @@ main {
208
168
209
169
</Sandpack>
210
170
211
-
Changing `mode` preserves the state of the children. Removing the boundary or
212
-
changing a child's type, key, or position can
213
-
[reset its state](/learn/preserving-and-resetting-state).
171
+
Changing `mode` preserves the state of the children. Removing the boundary or changing a child's type, key, or position can [reset its state](/learn/preserving-and-resetting-state).
214
172
215
173
---
216
174
217
175
### Preserving DOM state while content is hidden {/*restoring-the-dom-of-hidden-components*/}
218
176
219
-
An Activity boundary also preserves state held by the browser in DOM nodes. This
220
-
includes an uncontrolled input's current value, scroll position, and media
221
-
playback position.
177
+
An Activity boundary also preserves state held by the browser in DOM nodes. This includes an uncontrolled input's current value, scroll position, and media playback position.
222
178
223
-
In this example, enter a draft in the Contact section, switch sections, and then
224
-
return to Contact. The `<textarea>` value remains because its DOM node was hidden
225
-
rather than removed.
179
+
In this example, enter a draft in the Contact section, switch sections, and then return to Contact. The `<textarea>` value remains because its DOM node was hidden rather than removed.
226
180
227
181
<Sandpack>
228
182
@@ -306,18 +260,13 @@ textarea {
306
260
307
261
</Sandpack>
308
262
309
-
Preserving DOM state also means that DOM behavior can continue while content is
310
-
hidden. See [Troubleshooting](#my-hidden-components-have-unwanted-side-effects)
311
-
for DOM behavior that requires explicit cleanup.
263
+
Preserving DOM state also means that DOM behavior can continue while content is hidden. See [Troubleshooting](#my-hidden-components-have-unwanted-side-effects) for DOM behavior that requires explicit cleanup.
312
264
313
265
---
314
266
315
267
### Pre-rendering content that is likely to become visible {/*pre-rendering-content-thats-likely-to-become-visible*/}
316
268
317
-
An Activity boundary can also prepare content before the user sees it. Content
318
-
inside a hidden boundary renders at a lower priority without running Effects
319
-
created with `useEffect` or `useLayoutEffect`. This lets the content load code and
320
-
render-time data without delaying updates to visible content:
269
+
An Activity boundary can also prepare content before the user sees it. Content inside a hidden boundary renders at a lower priority without running Effects created with `useEffect` or `useLayoutEffect`. This lets the content load code and render-time data without delaying updates to visible content:
321
270
322
271
```js
323
272
<Suspense fallback={<Loading />}>
@@ -327,13 +276,9 @@ render-time data without delaying updates to visible content:
327
276
</Suspense>
328
277
```
329
278
330
-
If `Posts` suspends while reading code or data, React continues rendering the rest
331
-
of the page. If that hidden work completes, switching to the Posts tab can reveal
332
-
the content without waiting for the same work again.
279
+
If `Posts` suspends while reading code or data, React continues rendering the rest of the page. If that hidden work completes, switching to the Posts tab can reveal the content without waiting for the same work again.
333
280
334
-
The following example renders the Posts tab in a hidden Activity boundary when the
335
-
page first loads. Wait briefly before selecting **Posts**. The list is available
336
-
immediately because the hidden render started loading it in the background.
281
+
The following example renders the Posts tab in a hidden Activity boundary when the page first loads. Wait briefly before selecting **Posts**. The list is available immediately because the hidden render started loading it in the background.
337
282
338
283
<Sandpack>
339
284
@@ -423,31 +368,21 @@ button {
423
368
424
369
</Sandpack>
425
370
426
-
If the user selects Posts before the hidden render finishes, the nearest Suspense
427
-
fallback appears until the data is ready. Activity improves the likely case where
428
-
the background work finishes first; it does not guarantee that the content will
429
-
always be ready.
371
+
If the user selects Posts before the hidden render finishes, the nearest Suspense fallback appears until the data is ready. Activity improves the likely case where the background work finishes first; it does not guarantee that the content will always be ready.
430
372
431
373
<Note>
432
374
433
-
Only code and data read during rendering can load during pre-rendering. Activity
434
-
does not run Effects in hidden content, so data fetched inside an Effect does not
435
-
load until the boundary becomes visible.
375
+
Only code and data read during rendering can load during pre-rendering. Activity does not run Effects in hidden content, so data fetched inside an Effect does not load until the boundary becomes visible.
436
376
437
-
The data source must integrate with Suspense. For example, the component can read a
438
-
cached Promise with [`use`](/reference/react/use). See
439
-
[what activates a Suspense boundary](/reference/react/Suspense#what-activates-a-suspense-boundary).
377
+
The data source must integrate with Suspense. For example, the component can read a cached Promise with [`use`](/reference/react/use). See [what activates a Suspense boundary](/reference/react/Suspense#what-activates-a-suspense-boundary).
Activity boundaries also divide server-rendered pages into units that React can
448
-
hydrate independently. This is related to the selective hydration behavior of
449
-
[`<Suspense>`](/reference/react/Suspense), but it does not require displaying a
450
-
fallback in the initial UI.
385
+
Activity boundaries also divide server-rendered pages into units that React can hydrate independently. This is related to the selective hydration behavior of [`<Suspense>`](/reference/react/Suspense), but it does not require displaying a fallback in the initial UI.
451
386
452
387
For example, without a boundary React hydrates this page as one unit:
453
388
@@ -462,8 +397,7 @@ function Page() {
462
397
}
463
398
```
464
399
465
-
Wrapping `Comments` in an always-visible Activity boundary creates a separate
466
-
hydration unit:
400
+
Wrapping `Comments` in an always-visible Activity boundary creates a separate hydration unit:
467
401
468
402
```js
469
403
functionPage() {
@@ -478,10 +412,7 @@ function Page() {
478
412
}
479
413
```
480
414
481
-
The boundary is visible because the `mode` prop defaults to `'visible'`. Its
482
-
server-rendered HTML remains visible, but React can hydrate it independently from
483
-
the surrounding page. If the user interacts with that content before React reaches
484
-
it, React prioritizes hydrating the boundary.
415
+
The boundary is visible because the `mode` prop defaults to `'visible'`. Its server-rendered HTML remains visible, but React can hydrate it independently from the surrounding page. If the user interacts with that content before React reaches it, React prioritizes hydrating the boundary.
485
416
486
417
You can also use visible and hidden Activity boundaries for tabbed content:
487
418
@@ -509,34 +440,23 @@ function Page() {
509
440
}
510
441
```
511
442
512
-
React does not include initially hidden `<Activity>` content in server-rendered HTML.
513
-
On the client, React hydrates the visible content first and renders the hidden
514
-
content later at a lower priority. Initially visible boundaries are included in the
515
-
server-rendered HTML and can be hydrated independently. This allows the visible tab
516
-
and the controls around it to become interactive without waiting for React to
517
-
render the initially hidden tab.
443
+
React does not include initially hidden `<Activity>` content in server-rendered HTML. On the client, React hydrates the visible content first and renders the hidden content later at a lower priority. Initially visible boundaries are included in the server-rendered HTML and can be hydrated independently. This allows the visible tab and the controls around it to become interactive without waiting for React to render the initially hidden tab.
518
444
519
445
---
520
446
521
447
## Troubleshooting {/*troubleshooting*/}
522
448
523
449
### My hidden components have unwanted side effects {/*my-hidden-components-have-unwanted-side-effects*/}
524
450
525
-
`<Activity>` hides DOM nodes without removing them. Browser-managed behavior from
526
-
elements such as `<video>`, `<audio>`, and `<iframe>` can therefore continue while
527
-
the boundary is hidden.
451
+
`<Activity>` hides DOM nodes without removing them. Browser-managed behavior from elements such as `<video>`, `<audio>`, and `<iframe>` can therefore continue while the boundary is hidden.
528
452
529
453
<Pitfall>
530
454
531
455
##### Preserved media can continue playing {/*preserved-media-can-continue-playing*/}
532
456
533
-
Unmounting a `<video>` element stops playback because the browser removes the DOM
534
-
node. Hiding it with Activity preserves the node, so playback continues unless the
535
-
component pauses it explicitly.
457
+
Unmounting a `<video>` element stops playback because the browser removes the DOM node. Hiding it with Activity preserves the node, so playback continues unless the component pauses it explicitly.
536
458
537
-
Add the corresponding cleanup to an Effect. For behavior that must stop at the
Add the corresponding cleanup to an Effect. For behavior that must stop at the same time React hides the boundary, use [`useLayoutEffect`](/reference/react/useLayoutEffect):
540
460
541
461
```js
542
462
import { useLayoutEffect, useRef } from'react';
@@ -556,17 +476,11 @@ function VideoPlayer({ src }) {
556
476
}
557
477
```
558
478
559
-
React runs the cleanup when an enclosing Activity boundary becomes hidden. Because
560
-
the `<video>` node remains in the DOM, its playback position is preserved for when
561
-
the boundary becomes visible again.
479
+
React runs the cleanup when an enclosing Activity boundary becomes hidden. Because the `<video>` node remains in the DOM, its playback position is preserved for when the boundary becomes visible again.
562
480
563
-
The `useLayoutEffect` cleanup runs as part of hiding the UI. A cleanup from
564
-
`useEffect` can run later if, for example, a Suspense boundary suspends or a View
565
-
Transition is in progress.
481
+
The `useLayoutEffect` cleanup runs as part of hiding the UI. A cleanup from `useEffect` can run later if, for example, a Suspense boundary suspends or a View Transition is in progress.
566
482
567
-
This complete example pauses the video when you switch to Home while preserving
568
-
its playback position. When you return to Video, playback can continue from the
569
-
same position without recreating the element or downloading it again.
483
+
This complete example pauses the video when you switch to Home while preserving its playback position. When you return to Video, playback can continue from the same position without recreating the element or downloading it again.
570
484
571
485
<Sandpack>
572
486
@@ -651,16 +565,11 @@ video {
651
565
652
566
### My hidden components have Effects that are not running {/*my-hidden-components-have-effects-that-arent-running*/}
653
567
654
-
React runs cleanup functions for Effects created with `useEffect` and
655
-
`useLayoutEffect` when an Activity boundary becomes hidden. It runs their setup
656
-
functions again when the boundary becomes visible.
568
+
React runs cleanup functions for Effects created with `useEffect` and `useLayoutEffect` when an Activity boundary becomes hidden. It runs their setup functions again when the boundary becomes visible.
657
569
658
-
An Effect inside a hidden Activity boundary cannot remain active. Move ongoing
659
-
work that must continue while the UI is hidden to a component outside the boundary,
660
-
or keep the boundary visible.
570
+
An Effect inside a hidden Activity boundary cannot remain active. Move ongoing work that must continue while the UI is hidden to a component outside the boundary, or keep the boundary visible.
661
571
662
-
If an Effect controls an external system, return a cleanup function so hiding the
663
-
boundary disconnects from that system:
572
+
If an Effect controls an external system, return a cleanup function so hiding the boundary disconnects from that system:
664
573
665
574
```js
666
575
useEffect(() => {
@@ -673,6 +582,4 @@ useEffect(() => {
673
582
}, []);
674
583
```
675
584
676
-
Use [`<StrictMode>`](/reference/react/StrictMode) to find Effects that do not clean
677
-
up correctly. Strict Mode performs an additional setup and cleanup cycle in
678
-
development.
585
+
Use [`<StrictMode>`](/reference/react/StrictMode) to find Effects that do not clean up correctly. Strict Mode performs an additional setup and cleanup cycle in development.
0 commit comments