diff --git a/src/content/blog/2024/04/25/react-19-upgrade-guide.md b/src/content/blog/2024/04/25/react-19-upgrade-guide.md index 6f918a2a97b..a69b46d8939 100644 --- a/src/content/blog/2024/04/25/react-19-upgrade-guide.md +++ b/src/content/blog/2024/04/25/react-19-upgrade-guide.md @@ -129,7 +129,7 @@ For a list of all available codemods, see the [`react-codemod` repo](https://git In previous versions of React, errors thrown during render were caught and rethrown. In DEV, we would also log to `console.error`, resulting in duplicate error logs. -In React 19, we've [improved how errors are handled](/blog/2024/04/25/react-19#error-handling) to reduce duplication by not re-throwing: +In React 19, we've [improved how errors are handled](/blog/2024/12/05/react-19#error-handling) to reduce duplication by not re-throwing: - **Uncaught Errors**: Errors that are not caught by an Error Boundary are reported to `window.reportError`. - **Caught Errors**: Errors that are caught by an Error Boundary are reported to `console.error`. @@ -499,7 +499,7 @@ function AutoselectingInput() { ### Deprecated: `element.ref` {/*deprecated-element-ref*/} -React 19 supports [`ref` as a prop](/blog/2024/04/25/react-19#ref-as-a-prop), so we're deprecating the `element.ref` in place of `element.props.ref`. +React 19 supports [`ref` as a prop](/blog/2024/12/05/react-19#ref-as-a-prop), so we're deprecating the `element.ref` in place of `element.props.ref`. Accessing `element.ref` will warn: diff --git a/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md b/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md index dbd673a2910..95821fc43cf 100644 --- a/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md +++ b/src/content/blog/2025/04/23/react-labs-view-transitions-activity-and-more.md @@ -1245,8 +1245,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -2442,8 +2442,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -3670,8 +3670,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -4879,8 +4879,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -6195,8 +6195,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -7493,8 +7493,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -8814,8 +8814,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -10155,8 +10155,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -11441,8 +11441,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -12840,8 +12840,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { @@ -14178,8 +14178,8 @@ root.render( ```json package.json hidden { "dependencies": { - "react": "canary", - "react-dom": "canary", + "react": "19.3.0-canary-eb8feb71-20260814", + "react-dom": "19.3.0-canary-eb8feb71-20260814", "react-scripts": "latest" }, "scripts": { diff --git a/src/content/reference/react-dom/browser.md b/src/content/reference/react-dom/browser.md new file mode 100644 index 00000000000..017da34e7d2 --- /dev/null +++ b/src/content/reference/react-dom/browser.md @@ -0,0 +1,324 @@ +--- +title: browser +version: canary +--- + + + + + +**The `browser` API is currently only available in React’s Canary and Experimental channels.** + +[Learn more about React’s release channels here.](/community/versioning-policy#all-release-channels) + + + +`browser` lets you mark a component as browser-only during server rendering. + +```js +use(browser(reason?)) +``` + + + + + +--- + +## Reference {/*reference*/} + +### `browser(reason?)` {/*browser*/} + +Call `browser` inside [`use`](/reference/react/use) to mark a component as browser-only during server rendering: + +```js +import { use } from 'react'; +import { browser } from 'react-dom'; + +function BrowserOnly() { + use(browser('This component requires browser APIs.')); + return ; +} +``` + +During server rendering, `use(browser())` stops rendering the component and leaves the closest [``](/reference/react/Suspense) boundary's fallback in its place. In the browser, `use(browser())` returns `undefined`, so the component renders normally. + +[See more examples below.](#usage) + +#### Parameters {/*parameters*/} + +* **optional** `reason`: A string or function that explains why the content needs to render in the browser. The string or the function's return value becomes the `cause` of the `Error` passed to [`onBrowserBailout`](#reporting-browser-only-rendering-on-the-server). React calls a reason function each time a server renderer encounters the value returned by `browser`, but does not call it in the browser. If creating the reason is expensive, pass a function such as `() => new Error(...)`. + +#### Returns {/*returns*/} + +`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`. + +#### Caveats {/*caveats*/} + +* `use(browser())` must be inside a `` boundary during server rendering. Without one, the server render fails. +* In a React Server Components app, `use(browser())` must be called from a [Client Component](/reference/rsc/use-client), not a [Server Component](/reference/rsc/server-components). +* Calling `browser()` by itself has no effect. To mark a component as browser-only, pass the value returned by `browser` to `use`. Do not throw it. + +--- + +## Usage {/*usage*/} + +### Rendering content only in the browser {/*rendering-content-only-in-the-browser*/} + +Call `browser` inside `use` in a component that should only render in the browser: + +You can use this instead of checking `typeof window`, waiting for an [`Effect`](/reference/react/useEffect) to set mounted state, or using a framework option to disable server rendering. + +Click **Reload** to see the loading fallback in the initial HTML. After hydration, React displays the draft loaded from `localStorage`. + + + +```js src/App.js active +import { Suspense, use, useState } from 'react'; +import { browser } from 'react-dom'; + +function SavedDraft() { + use(browser('The draft is stored in localStorage.')); + const [draft, setDraft] = useState( + () => localStorage.getItem('draft') ?? '' + ); + + function handleChange(event) { + const nextDraft = event.target.value; + setDraft(nextDraft); + localStorage.setItem('draft', nextDraft); + } + + return ( +