Skip to content

Commit 5b3692a

Browse files
Clarify browser-only rendering guidance (#8612)
* Clarify browser-only rendering guidance * Polish browser-only guidance wording * Use Canary markers in browser guidance * Present browser as a use resource * Polish browser usage labels * Address browser guidance review * Clarify browser return value is opaque * Restore alternative wording * Restore hydration alternative wording * Focus use introduction on resources * Note stable browser cleanup
1 parent 96ad418 commit 5b3692a

5 files changed

Lines changed: 19 additions & 5 deletions

File tree

src/content/reference/react-dom/browser.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ During server rendering, `use(browser())` stops rendering the component and leav
5151
5252
#### Returns {/*returns*/}
5353
54-
`browser` returns a value that you can pass to `use` in a component or use as the reason when [aborting a server render](#aborting-pending-server-rendering-for-the-browser). In the browser, passing this value to `use` returns `undefined`.
54+
`browser` returns an opaque value that you can pass to `use` in a component or use as the reason when [aborting a server render](#aborting-pending-server-rendering-for-the-browser). In the browser, passing this value to `use` returns `undefined`.
5555
5656
#### Caveats {/*caveats*/}
5757

src/content/reference/react-dom/client/hydrateRoot.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,8 @@ This only works one level deep, and is intended to be an escape hatch. Don’t o
274274
275275
---
276276
277+
{/* TODO: Remove this subsection when browser is available in Stable. */}
278+
277279
### Handling different client and server content {/*handling-different-client-and-server-content*/}
278280
279281
If you intentionally need to render something different on the server and the client, you can do a two-pass rendering. Components that render something different on the client can read a [state variable](/reference/react/useState) like `isClient`, which you can set to `true` in an [Effect](/reference/react/useEffect):
@@ -319,6 +321,10 @@ export default function App() {
319321
320322
This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration.
321323
324+
Use this approach when you want the client-rendered content to be different from the initial server-rendered HTML.
325+
326+
<Canary>If a component should render only in the browser, call [`use(browser())`](/reference/react/use#use-browser) instead of waiting for an Effect.</Canary>
327+
322328
<Pitfall>
323329
324330
This approach makes hydration slower because your components have to render twice. Be mindful of the user experience on slow connections. The JavaScript code may load significantly later than the initial HTML render, so rendering a different UI immediately after hydration may also feel jarring to the user.

src/content/reference/react/apis.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,17 @@ In addition to [Hooks](/reference/react/hooks) and [Components](/reference/react
2525

2626
*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.
2727

28-
To read a value from a resource, use this API:
28+
You can pass these types of resources to [`use`](/reference/react/use):
29+
30+
* A [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) to read its resolved value.
31+
* A [context](/learn/passing-data-deeply-with-context) to read its value.
32+
* <CanaryBadge /> The value returned by [`browser`](/reference/react-dom/browser) to mark a component as browser-only during server rendering.
2933

30-
* [`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).
3134
```js
3235
function MessageComponent({ messagePromise }) {
3336
const message = use(messagePromise);
3437
const theme = use(ThemeContext);
38+
use(browser());
3539
// ...
3640
}
3741
```

src/content/reference/react/use.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ title: use
44

55
<Intro>
66

7-
`use` is a React API that lets you read the value of a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or [context](/learn/passing-data-deeply-with-context).
7+
`use` is a React API that lets you read a resource during rendering, such as a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) or [context](/learn/passing-data-deeply-with-context).
88

99
```js
1010
const value = use(resource);
@@ -1326,6 +1326,8 @@ async function getData(url) {
13261326
13271327
---
13281328
1329+
## Usage (Browser) {/*usage-browser*/}
1330+
13291331
### <CanaryBadge /> Rendering a component only in the browser {/*rendering-a-component-only-in-the-browser*/}
13301332
13311333
Pass the value returned by [`browser`](/reference/react-dom/browser) to `use` inside a component that should only render in the browser.

src/content/reference/react/useLayoutEffect.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,9 @@ However, if you're running into this problem, you have a few different options:
734734
735735
- Replace `useLayoutEffect` with [`useEffect`.](/reference/react/useEffect) This tells React that it's okay to display the initial render result without blocking the paint (because the original HTML will become visible before your Effect runs).
736736
737-
- Alternatively, [mark your component as client-only.](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content) This tells React to replace its content up to the closest [`<Suspense>`](/reference/react/Suspense) boundary with a loading fallback (for example, a spinner or a glimmer) during server rendering.
737+
- <CanaryBadge /> Alternatively, call [`use(browser())`](/reference/react/use#use-browser) to mark the component as browser-only. React will replace its content up to the closest [`<Suspense>`](/reference/react/Suspense) boundary with a loading fallback (for example, a spinner or a glimmer) during server rendering.
738+
739+
- Alternatively, [mark your component as client-only.](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content) This tells React to replace its content up to the closest `<Suspense>` boundary with a loading fallback during server rendering.
738740
739741
- Alternatively, you can render a component with `useLayoutEffect` only after hydration. Keep a boolean `isMounted` state that's initialized to `false`, and set it to `true` inside a `useEffect` call. Your rendering logic can then be like `return isMounted ? <RealContent /> : <FallbackContent />`. On the server and during the hydration, the user will see `FallbackContent` which should not call `useLayoutEffect`. Then React will replace it with `RealContent` which runs on the client only and can include `useLayoutEffect` calls.
740742

0 commit comments

Comments
 (0)