`.
- Usually, you will use refs for non-destructive actions like focusing, scrolling, or measuring DOM elements.
-- A component doesn't expose its DOM nodes by default. You can opt into exposing a DOM node by using `forwardRef` and passing the second `ref` argument down to a specific node.
+- A component doesn't expose its DOM nodes by default. You can opt into exposing a DOM node by using the `ref` prop.
- Avoid changing DOM nodes managed by React.
- If you do modify DOM nodes managed by React, modify parts that React has no reason to update.
@@ -1117,7 +1049,7 @@ Make it so that clicking the "Search" button puts focus into the field. Note tha
-You'll need `forwardRef` to opt into exposing a DOM node from your own component like `SearchInput`.
+You'll need to pass `ref` as a prop to opt into exposing a DOM node from your own component like `SearchInput`.
@@ -1202,18 +1134,14 @@ export default function SearchButton({ onClick }) {
```
```js src/SearchInput.js
-import { forwardRef } from 'react';
-
-export default forwardRef(
- function SearchInput(props, ref) {
- return (
-
- );
- }
-);
+export default function SearchInput({ ref }) {
+ return (
+
+ );
+}
```
```css
diff --git a/src/content/learn/passing-data-deeply-with-context.md b/src/content/learn/passing-data-deeply-with-context.md
index 1aea87b354..e81678c8e2 100644
--- a/src/content/learn/passing-data-deeply-with-context.md
+++ b/src/content/learn/passing-data-deeply-with-context.md
@@ -468,15 +468,15 @@ import { LevelContext } from './LevelContext.js';
export default function Section({ level, children }) {
return (
);
}
```
-This tells React: "if any component inside this `
` asks for `LevelContext`, give them this `level`." The component will use the value of the nearest `` in the UI tree above it.
+This tells React: "if any component inside this `` asks for `LevelContext`, give them this `level`." The component will use the value of the nearest `` in the UI tree above it.
@@ -514,9 +514,9 @@ import { LevelContext } from './LevelContext.js';
export default function Section({ level, children }) {
return (
);
}
@@ -567,7 +567,7 @@ export const LevelContext = createContext(1);
It's the same result as the original code, but you did not need to pass the `level` prop to each `Heading` component! Instead, it "figures out" its heading level by asking the closest `Section` above:
1. You pass a `level` prop to the ``.
-2. `Section` wraps its children into ``.
+2. `Section` wraps its children into ``.
3. `Heading` asks the closest value of `LevelContext` above with `useContext(LevelContext)`.
## Using and providing context from the same component {/*using-and-providing-context-from-the-same-component*/}
@@ -595,9 +595,9 @@ export default function Section({ children }) {
const level = useContext(LevelContext);
return (
);
}
@@ -643,9 +643,9 @@ export default function Section({ children }) {
const level = useContext(LevelContext);
return (
);
}
@@ -776,9 +776,9 @@ export default function Section({ children, isFancy }) {
'section ' +
(isFancy ? 'fancy' : '')
}>
-
+
{children}
-
+
);
}
@@ -868,7 +868,7 @@ In general, if some information is needed by distant components in different par
* To pass context:
1. Create and export it with `export const MyContext = createContext(defaultValue)`.
2. Pass it to the `useContext(MyContext)` Hook to read it in any child component, no matter how deep.
- 3. Wrap children into `
` to provide it from a parent.
+ 3. Wrap children into `` to provide it from a parent.
* Context passes through any components in the middle.
* Context lets you write components that "adapt to their surroundings".
* Before you use context, try passing props or passing JSX as `children`.
@@ -1022,7 +1022,7 @@ li {
Remove `imageSize` prop from all the components.
-Create and export `ImageSizeContext` from `Context.js`. Then wrap the List into `` to pass the value down, and `useContext(ImageSizeContext)` to read it in the `PlaceImage`:
+Create and export `ImageSizeContext` from `Context.js`. Then wrap the List into `` to pass the value down, and `useContext(ImageSizeContext)` to read it in the `PlaceImage`:
@@ -1036,7 +1036,7 @@ export default function App() {
const [isLarge, setIsLarge] = useState(false);
const imageSize = isLarge ? 150 : 100;
return (
-
-
+
)
}
diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md
index 5362d69e1d..7c46673e7a 100644
--- a/src/content/learn/react-compiler.md
+++ b/src/content/learn/react-compiler.md
@@ -311,7 +311,7 @@ export default defineConfig({
### Webpack {/*usage-with-webpack*/}
-A community Webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack).
+A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack).
### Expo {/*usage-with-expo*/}
@@ -347,7 +347,7 @@ React Compiler can verify many of the Rules of React statically, and will safely
### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/}
-[React Devtools](/learn/react-developer-tools) (v5.0+) has built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler.
+[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler.
### Something is not working after compilation {/*something-is-not-working-after-compilation*/}
If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized.
diff --git a/src/content/learn/react-developer-tools.md b/src/content/learn/react-developer-tools.md
index c554df9c6f..9efc4fcf99 100644
--- a/src/content/learn/react-developer-tools.md
+++ b/src/content/learn/react-developer-tools.md
@@ -53,6 +53,7 @@ react-devtools

+<<<<<<< HEAD
## Мобильные устройства (React Native) {/*mobile-react-native*/}
React Developer Tools также можно использовать для отладки приложений, созданных с помощью [React Native](https://reactnative.dev/).
Самый простой способ использования React Developer Tools - установить их глобально:
@@ -60,11 +61,15 @@ React Developer Tools также можно использовать для от
```bash
# Yarn
yarn global add react-devtools
+=======
+## Mobile (React Native) {/*mobile-react-native*/}
-# Npm
-npm install -g react-devtools
-```
+To inspect apps built with [React Native](https://reactnative.dev/), you can use [React Native DevTools](https://reactnative.dev/docs/react-native-devtools), the built-in debugger that deeply integrates React Developer Tools. All features work identically to the browser extension, including native element highlighting and selection.
+>>>>>>> f6d762cbbf958ca45bb8d1d011b31e5289e43a3d
+
+[Learn more about debugging in React Native.](https://reactnative.dev/docs/debugging)
+<<<<<<< HEAD
Откройте инструменты разработчика в терминале.
```bash
react-devtools
@@ -75,3 +80,6 @@ react-devtools
> Попробуйте перезагрузить приложение, если инструменты разработчика не подключатся через несколько секунд.
[Узнайте больше о отладке React Native.](https://reactnative.dev/docs/debugging)
+=======
+> For versions of React Native earlier than 0.76, please use the standalone build of React DevTools by following the [Safari and other browsers](#safari-and-other-browsers) guide above.
+>>>>>>> f6d762cbbf958ca45bb8d1d011b31e5289e43a3d
diff --git a/src/content/learn/render-and-commit.md b/src/content/learn/render-and-commit.md
index 016f372848..836f143bea 100644
--- a/src/content/learn/render-and-commit.md
+++ b/src/content/learn/render-and-commit.md
@@ -70,7 +70,7 @@ export default function Image() {
После того как компонент был первоначально отрендерен, вы можете инициировать последующие рендеры, обновляя его состояние с помощью функции [`set`](/reference/react/useState#setstate). Обновление состояние компонента автоматически ставит его в очередь на рендер. (Вы можете представить это как посетитель ресторана, который после первого заказа заказывает чай, десерт и всевозможные вещи, в зависимости от состояния жажды или голода).
-
+
@@ -84,7 +84,11 @@ export default function Image() {
Этот процесс рекурсивен: если обновленный компонент возвращает какой-то другой компонент, React будет рендерить _этот_ компонент следующим, и если этот компонент тоже что-то возвращает, он будет рендерить _этот_ компонент следующим, и так далее. Этот процесс будет продолжаться до тех пор, пока не останется вложенных компонентов и React не будет точно знать, что должно быть отображено на экране.
+<<<<<<< HEAD
В следующем примере React вызовет `Gallery()` и `Image()` несколько раз:
+=======
+In the following example, React will call `Gallery()` and `Image()` several times:
+>>>>>>> f6d762cbbf958ca45bb8d1d011b31e5289e43a3d
@@ -148,10 +152,17 @@ img { margin: 0 10px 10px 0; }
## Часть 3: React фиксирует изменения в DOM {/*step-3-react-commits-changes-to-the-dom*/}
+<<<<<<< HEAD
После рендеринга (вызова) ваших компонентов React модифицирует DOM.
* **На начальном рендере,** React использует [`appendChild()`](https://developer.mozilla.org/ru/docs/Web/API/Node/appendChild) DOM API, чтобы вставить все DOM ноды, которые он создал на экране.
* **Для ре-рендеров,** React будет применять минимально необходимые операции (вычисляемые во время рендеринга!), чтобы DOM соответствовал последнему выводу рендеринга.
+=======
+After rendering (calling) your components, React will modify the DOM.
+
+* **For the initial render,** React will use the [`appendChild()`](https://developer.mozilla.org/docs/Web/API/Node/appendChild) DOM API to put all the DOM nodes it has created on screen.
+* **For re-renders,** React will apply the minimal necessary operations (calculated while rendering!) to make the DOM match the latest rendering output.
+>>>>>>> f6d762cbbf958ca45bb8d1d011b31e5289e43a3d
**React изменяет узлы DOM только если есть разница между рендерами.** Например, вот компонент, который рендерится с разными пропсами, передаваемыми от родителя каждую секунду. Обратите внимание, как вы можете добавить некоторый текст в ``, обновляя его `значение`, но текст не исчезает при повторном рендеринге компонента:
diff --git a/src/content/learn/setup.md b/src/content/learn/setup.md
new file mode 100644
index 0000000000..2c46ee1485
--- /dev/null
+++ b/src/content/learn/setup.md
@@ -0,0 +1,28 @@
+---
+title: Setup
+---
+
+
+React integrates with tools like editors, TypeScript, browser extensions, and compilers. This section will help you get your environment set up.
+
+
+
+## Editor Setup {/*editor-setup*/}
+
+See our [recommended editors](/learn/editor-setup) and learn how to set them up to work with React.
+
+## Using TypeScript {/*using-typescript*/}
+
+TypeScript is a popular way to add type definitions to JavaScript codebases. [Learn how to integrate TypeScript into your React projects](/learn/typescript).
+
+## React Developer Tools {/*react-developer-tools*/}
+
+React Developer Tools is a browser extension that can inspect React components, edit props and state, and identify performance problems. Learn how to install it [here](learn/react-developer-tools).
+
+## React Compiler {/*react-compiler*/}
+
+React Compiler is a tool that automatically optimizes your React app. [Learn more](/learn/react-compiler).
+
+## Next steps {/*next-steps*/}
+
+Head to the [Quick Start](/learn) guide for a tour of the most important React concepts you will encounter every day.
diff --git a/src/content/learn/state-a-components-memory.md b/src/content/learn/state-a-components-memory.md
index 75a1fd0b91..73d46bdab8 100644
--- a/src/content/learn/state-a-components-memory.md
+++ b/src/content/learn/state-a-components-memory.md
@@ -1452,7 +1452,7 @@ If your linter is [configured for React](/learn/editor-setup#linting), you shoul
#### Remove unnecessary state {/*remove-unnecessary-state*/}
-When the button is clicked, this example should ask for the user's name and then display an alert greeting them. You tried to use state to keep the name, but for some reason it always shows "Hello, !".
+When the button is clicked, this example should ask for the user's name and then display an alert greeting them. You tried to use state to keep the name, but for some reason the first time it shows "Hello, !", and then "Hello, [name]!" with the previous input every time after.
To fix this code, remove the unnecessary state variable. (We will discuss about [why this didn't work](/learn/state-as-a-snapshot) later.)
diff --git a/src/content/learn/tutorial-tic-tac-toe.md b/src/content/learn/tutorial-tic-tac-toe.md
index 6487e8007f..1c61d180a4 100644
--- a/src/content/learn/tutorial-tic-tac-toe.md
+++ b/src/content/learn/tutorial-tic-tac-toe.md
@@ -295,7 +295,7 @@ export default function Square() {
}
```
-The _browser_ section should be displaying a square with a X in it like this:
+The _browser_ section should be displaying a square with an X in it like this:

@@ -1325,7 +1325,7 @@ Let's recap what happens when a user clicks the top left square on your board to
1. `handleClick` uses the argument (`0`) to update the first element of the `squares` array from `null` to `X`.
1. The `squares` state of the `Board` component was updated, so the `Board` and all of its children re-render. This causes the `value` prop of the `Square` component with index `0` to change from `null` to `X`.
-In the end the user sees that the upper left square has changed from empty to having a `X` after clicking it.
+In the end the user sees that the upper left square has changed from empty to having an `X` after clicking it.
@@ -1406,7 +1406,7 @@ But wait, there's a problem. Try clicking on the same square multiple times:
The `X` is overwritten by an `O`! While this would add a very interesting twist to the game, we're going to stick to the original rules for now.
-When you mark a square with a `X` or an `O` you aren't first checking to see if the square already has a `X` or `O` value. You can fix this by *returning early*. You'll check to see if the square already has a `X` or an `O`. If the square is already filled, you will `return` in the `handleClick` function early--before it tries to update the board state.
+When you mark a square with an `X` or an `O` you aren't first checking to see if the square already has an `X` or `O` value. You can fix this by *returning early*. You'll check to see if the square already has an `X` or an `O`. If the square is already filled, you will `return` in the `handleClick` function early--before it tries to update the board state.
```js {2,3,4}
function handleClick(i) {
@@ -1556,7 +1556,7 @@ It does not matter whether you define `calculateWinner` before or after the `Boa
-You will call `calculateWinner(squares)` in the `Board` component's `handleClick` function to check if a player has won. You can perform this check at the same time you check if a user has clicked a square that already has a `X` or and `O`. We'd like to return early in both cases:
+You will call `calculateWinner(squares)` in the `Board` component's `handleClick` function to check if a player has won. You can perform this check at the same time you check if a user has clicked a square that already has an `X` or an `O`. We'd like to return early in both cases:
```js {2}
function handleClick(i) {
diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md
index b336b6e5ed..0a39339498 100644
--- a/src/content/reference/react-dom/client/createRoot.md
+++ b/src/content/reference/react-dom/client/createRoot.md
@@ -45,8 +45,8 @@ An app fully built with React will usually only have one `createRoot` call for i
* **optional** `options`: An object with options for this React root.
- * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`.
- * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown, and an `errorInfo` object containing the `componentStack`.
+ * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`.
+ * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown, and an `errorInfo` object containing the `componentStack`.
* **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with an `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`.
* **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page.
@@ -144,7 +144,7 @@ Usually, you only need to run this code once at startup. It will:
-```html index.html
+```html public/index.html
My app
@@ -344,798 +344,127 @@ export default function App({counter}) {
It is uncommon to call `render` multiple times. Usually, your components will [update state](/reference/react/useState) instead.
-### Show a dialog for uncaught errors {/*show-a-dialog-for-uncaught-errors*/}
-
-
-
-`onUncaughtError` is only available in the latest React Canary release.
-
-
-
-By default, React will log all uncaught errors to the console. To implement your own error reporting, you can provide the optional `onUncaughtError` root option:
-
-```js [[1, 6, "onUncaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack"]]
-import { createRoot } from 'react-dom/client';
-
-const root = createRoot(
- document.getElementById('root'),
- {
- onUncaughtError: (error, errorInfo) => {
- console.error(
- 'Uncaught error',
- error,
- errorInfo.componentStack
- );
- }
- }
-);
-root.render();
-```
-
-The onUncaughtError option is a function called with two arguments:
-
-1. The error that was thrown.
-2. An errorInfo object that contains the componentStack of the error.
-
-You can use the `onUncaughtError` root option to display error dialogs:
+### Error logging in production {/*error-logging-in-production*/}
-
+By default, React will log all errors to the console. To implement your own error reporting, you can provide the optional error handler root options `onUncaughtError`, `onCaughtError` and `onRecoverableError`:
-```html index.html hidden
-
-
-
- My app
-
-
-
-
-
-
-
-
-
-
-
-
This error occurred at:
-
-
Call stack:
-
-
-
-
This error is not dismissible.
-
-
-
-
-
-```
-
-```css src/styles.css active
-label, button { display: block; margin-bottom: 20px; }
-html, body { min-height: 300px; }
-
-#error-dialog {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: white;
- padding: 15px;
- opacity: 0.9;
- text-wrap: wrap;
- overflow: scroll;
-}
-
-.text-red {
- color: red;
-}
-
-.-mb-20 {
- margin-bottom: -20px;
-}
-
-.mb-0 {
- margin-bottom: 0;
-}
-
-.mb-10 {
- margin-bottom: 10px;
-}
-
-pre {
- text-wrap: wrap;
-}
-
-pre.nowrap {
- text-wrap: nowrap;
-}
-
-.hidden {
- display: none;
-}
-```
-
-```js src/reportError.js hidden
-function reportError({ title, error, componentStack, dismissable }) {
- const errorDialog = document.getElementById("error-dialog");
- const errorTitle = document.getElementById("error-title");
- const errorMessage = document.getElementById("error-message");
- const errorBody = document.getElementById("error-body");
- const errorComponentStack = document.getElementById("error-component-stack");
- const errorStack = document.getElementById("error-stack");
- const errorClose = document.getElementById("error-close");
- const errorCause = document.getElementById("error-cause");
- const errorCauseMessage = document.getElementById("error-cause-message");
- const errorCauseStack = document.getElementById("error-cause-stack");
- const errorNotDismissible = document.getElementById("error-not-dismissible");
-
- // Set the title
- errorTitle.innerText = title;
-
- // Display error message and body
- const [heading, body] = error.message.split(/\n(.*)/s);
- errorMessage.innerText = heading;
- if (body) {
- errorBody.innerText = body;
- } else {
- errorBody.innerText = '';
- }
-
- // Display component stack
- errorComponentStack.innerText = componentStack;
-
- // Display the call stack
- // Since we already displayed the message, strip it, and the first Error: line.
- errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1];
-
- // Display the cause, if available
- if (error.cause) {
- errorCauseMessage.innerText = error.cause.message;
- errorCauseStack.innerText = error.cause.stack;
- errorCause.classList.remove('hidden');
- } else {
- errorCause.classList.add('hidden');
- }
- // Display the close button, if dismissible
- if (dismissable) {
- errorNotDismissible.classList.add('hidden');
- errorClose.classList.remove("hidden");
- } else {
- errorNotDismissible.classList.remove('hidden');
- errorClose.classList.add("hidden");
- }
-
- // Show the dialog
- errorDialog.classList.remove("hidden");
-}
-
-export function reportCaughtError({error, cause, componentStack}) {
- reportError({ title: "Caught Error", error, componentStack, dismissable: true});
-}
-
-export function reportUncaughtError({error, cause, componentStack}) {
- reportError({ title: "Uncaught Error", error, componentStack, dismissable: false });
-}
-
-export function reportRecoverableError({error, cause, componentStack}) {
- reportError({ title: "Recoverable Error", error, componentStack, dismissable: true });
-}
-```
-
-```js src/index.js active
+```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack", 15]]
import { createRoot } from "react-dom/client";
-import App from "./App.js";
-import {reportUncaughtError} from "./reportError";
-import "./styles.css";
+import { reportCaughtError } from "./reportError";
const container = document.getElementById("root");
const root = createRoot(container, {
- onUncaughtError: (error, errorInfo) => {
- if (error.message !== 'Known error') {
- reportUncaughtError({
+ onCaughtError: (error, errorInfo) => {
+ if (error.message !== "Known error") {
+ reportCaughtError({
error,
- componentStack: errorInfo.componentStack
+ componentStack: errorInfo.componentStack,
});
}
- }
-});
-root.render();
-```
-
-```js src/App.js
-import { useState } from 'react';
-
-export default function App() {
- const [throwError, setThrowError] = useState(false);
-
- if (throwError) {
- foo.bar = 'baz';
- }
-
- return (
-
- This error shows the error dialog:
-
-
- );
-}
-```
-
-```json package.json hidden
-{
- "dependencies": {
- "react": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0"
},
- "main": "/index.js"
-}
-```
-
-
-
-
-### Displaying Error Boundary errors {/*displaying-error-boundary-errors*/}
-
-
-
-`onCaughtError` is only available in the latest React Canary release.
-
-
-
-By default, React will log all errors caught by an Error Boundary to `console.error`. To override this behavior, you can provide the optional `onCaughtError` root option to handle errors caught by an [Error Boundary](/reference/react/Component#catching-rendering-errors-with-an-error-boundary):
-
-```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack"]]
-import { createRoot } from 'react-dom/client';
-
-const root = createRoot(
- document.getElementById('root'),
- {
- onCaughtError: (error, errorInfo) => {
- console.error(
- 'Caught error',
- error,
- errorInfo.componentStack
- );
- }
- }
-);
-root.render();
+});
```
The onCaughtError option is a function called with two arguments:
-1. The error that was caught by the boundary.
+1. The error that was thrown.
2. An errorInfo object that contains the componentStack of the error.
-You can use the `onCaughtError` root option to display error dialogs or filter known errors from logging:
+Together with `onUncaughtError` and `onRecoverableError`, you can can implement your own error reporting system:
-```html index.html hidden
-
-
-
- My app
-
-
-
-
-
-
-
-
-
-
-
-
This error occurred at:
-
-
Call stack:
-
-
-
-
This error is not dismissible.
-
-
-
-
-
-```
-
-```css src/styles.css active
-label, button { display: block; margin-bottom: 20px; }
-html, body { min-height: 300px; }
-
-#error-dialog {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: white;
- padding: 15px;
- opacity: 0.9;
- text-wrap: wrap;
- overflow: scroll;
-}
-
-.text-red {
- color: red;
-}
-
-.-mb-20 {
- margin-bottom: -20px;
-}
-
-.mb-0 {
- margin-bottom: 0;
+```js src/reportError.js
+function reportError({ type, error, errorInfo }) {
+ // The specific implementation is up to you.
+ // `console.error()` is only used for demonstration purposes.
+ console.error(type, error, "Component Stack: ");
+ console.error("Component Stack: ", errorInfo.componentStack);
}
-.mb-10 {
- margin-bottom: 10px;
-}
-
-pre {
- text-wrap: wrap;
-}
-
-pre.nowrap {
- text-wrap: nowrap;
-}
-
-.hidden {
- display: none;
-}
-```
-
-```js src/reportError.js hidden
-function reportError({ title, error, componentStack, dismissable }) {
- const errorDialog = document.getElementById("error-dialog");
- const errorTitle = document.getElementById("error-title");
- const errorMessage = document.getElementById("error-message");
- const errorBody = document.getElementById("error-body");
- const errorComponentStack = document.getElementById("error-component-stack");
- const errorStack = document.getElementById("error-stack");
- const errorClose = document.getElementById("error-close");
- const errorCause = document.getElementById("error-cause");
- const errorCauseMessage = document.getElementById("error-cause-message");
- const errorCauseStack = document.getElementById("error-cause-stack");
- const errorNotDismissible = document.getElementById("error-not-dismissible");
-
- // Set the title
- errorTitle.innerText = title;
-
- // Display error message and body
- const [heading, body] = error.message.split(/\n(.*)/s);
- errorMessage.innerText = heading;
- if (body) {
- errorBody.innerText = body;
- } else {
- errorBody.innerText = '';
- }
-
- // Display component stack
- errorComponentStack.innerText = componentStack;
-
- // Display the call stack
- // Since we already displayed the message, strip it, and the first Error: line.
- errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1];
-
- // Display the cause, if available
- if (error.cause) {
- errorCauseMessage.innerText = error.cause.message;
- errorCauseStack.innerText = error.cause.stack;
- errorCause.classList.remove('hidden');
- } else {
- errorCause.classList.add('hidden');
+export function onCaughtErrorProd(error, errorInfo) {
+ if (error.message !== "Known error") {
+ reportError({ type: "Caught", error, errorInfo });
}
- // Display the close button, if dismissible
- if (dismissable) {
- errorNotDismissible.classList.add('hidden');
- errorClose.classList.remove("hidden");
- } else {
- errorNotDismissible.classList.remove('hidden');
- errorClose.classList.add("hidden");
- }
-
- // Show the dialog
- errorDialog.classList.remove("hidden");
}
-export function reportCaughtError({error, cause, componentStack}) {
- reportError({ title: "Caught Error", error, componentStack, dismissable: true});
+export function onUncaughtErrorProd(error, errorInfo) {
+ reportError({ type: "Uncaught", error, errorInfo });
}
-export function reportUncaughtError({error, cause, componentStack}) {
- reportError({ title: "Uncaught Error", error, componentStack, dismissable: false });
-}
-
-export function reportRecoverableError({error, cause, componentStack}) {
- reportError({ title: "Recoverable Error", error, componentStack, dismissable: true });
+export function onRecoverableErrorProd(error, errorInfo) {
+ reportError({ type: "Recoverable", error, errorInfo });
}
```
```js src/index.js active
import { createRoot } from "react-dom/client";
import App from "./App.js";
-import {reportCaughtError} from "./reportError";
-import "./styles.css";
+import {
+ onCaughtErrorProd,
+ onRecoverableErrorProd,
+ onUncaughtErrorProd,
+} from "./reportError";
const container = document.getElementById("root");
const root = createRoot(container, {
- onCaughtError: (error, errorInfo) => {
- if (error.message !== 'Known error') {
- reportCaughtError({
- error,
- componentStack: errorInfo.componentStack,
- });
- }
- }
+ // Keep in mind to remove these options in development to leverage
+ // React's default handlers or implement your own overlay for development.
+ // The handlers are only specfied unconditionally here for demonstration purposes.
+ onCaughtError: onCaughtErrorProd,
+ onRecoverableError: onRecoverableErrorProd,
+ onUncaughtError: onUncaughtErrorProd,
});
root.render();
```
```js src/App.js
-import { useState } from 'react';
-import { ErrorBoundary } from "react-error-boundary";
-
-export default function App() {
- const [error, setError] = useState(null);
-
- function handleUnknown() {
- setError("unknown");
- }
+import { Component, useState } from "react";
- function handleKnown() {
- setError("known");
- }
-
- return (
- <>
- {
- setError(null);
- }}
- >
- {error != null && }
- This error will not show the error dialog:
-
- This error will show the error dialog:
-
-
-
- >
- );
+function Boom() {
+ foo.bar = "baz";
}
-function fallbackRender({ resetErrorBoundary }) {
- return (
-
-
Error Boundary
-
Something went wrong.
-
-
- );
-}
+class ErrorBoundary extends Component {
+ state = { hasError: false };
-function Throw({error}) {
- if (error === "known") {
- throw new Error('Known error')
- } else {
- foo.bar = 'baz';
+ static getDerivedStateFromError(error) {
+ return { hasError: true };
}
-}
-```
-```json package.json hidden
-{
- "dependencies": {
- "react": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0",
- "react-error-boundary": "4.0.3"
- },
- "main": "/index.js"
-}
-```
-
-
-
-### Displaying a dialog for recoverable errors {/*displaying-a-dialog-for-recoverable-errors*/}
-
-React may automatically render a component a second time to attempt to recover from an error thrown in render. If successful, React will log a recoverable error to the console to notify the developer. To override this behavior, you can provide the optional `onRecoverableError` root option:
-
-```js [[1, 6, "onRecoverableError"], [2, 6, "error", 1], [3, 10, "error.cause"], [4, 6, "errorInfo"], [5, 11, "componentStack"]]
-import { createRoot } from 'react-dom/client';
-
-const root = createRoot(
- document.getElementById('root'),
- {
- onRecoverableError: (error, errorInfo) => {
- console.error(
- 'Recoverable error',
- error,
- error.cause,
- errorInfo.componentStack,
- );
+ render() {
+ if (this.state.hasError) {
+ return Something went wrong.
;
}
+ return this.props.children;
}
-);
-root.render();
-```
-
-The onRecoverableError option is a function called with two arguments:
-
-1. The error that React throws. Some errors may include the original cause as error.cause.
-2. An errorInfo object that contains the componentStack of the error.
-
-You can use the `onRecoverableError` root option to display error dialogs:
-
-
-
-```html index.html hidden
-
-
-
- My app
-
-
-
-
-
-
-
-
-
-
-
-
This error occurred at:
-
-
Call stack:
-
-
-
-
This error is not dismissible.
-
-
-
-
-
-```
-
-```css src/styles.css active
-label, button { display: block; margin-bottom: 20px; }
-html, body { min-height: 300px; }
-
-#error-dialog {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: white;
- padding: 15px;
- opacity: 0.9;
- text-wrap: wrap;
- overflow: scroll;
-}
-
-.text-red {
- color: red;
}
-.-mb-20 {
- margin-bottom: -20px;
-}
-
-.mb-0 {
- margin-bottom: 0;
-}
-
-.mb-10 {
- margin-bottom: 10px;
-}
-
-pre {
- text-wrap: wrap;
-}
-
-pre.nowrap {
- text-wrap: nowrap;
-}
-
-.hidden {
- display: none;
-}
-```
-
-```js src/reportError.js hidden
-function reportError({ title, error, componentStack, dismissable }) {
- const errorDialog = document.getElementById("error-dialog");
- const errorTitle = document.getElementById("error-title");
- const errorMessage = document.getElementById("error-message");
- const errorBody = document.getElementById("error-body");
- const errorComponentStack = document.getElementById("error-component-stack");
- const errorStack = document.getElementById("error-stack");
- const errorClose = document.getElementById("error-close");
- const errorCause = document.getElementById("error-cause");
- const errorCauseMessage = document.getElementById("error-cause-message");
- const errorCauseStack = document.getElementById("error-cause-stack");
- const errorNotDismissible = document.getElementById("error-not-dismissible");
-
- // Set the title
- errorTitle.innerText = title;
-
- // Display error message and body
- const [heading, body] = error.message.split(/\n(.*)/s);
- errorMessage.innerText = heading;
- if (body) {
- errorBody.innerText = body;
- } else {
- errorBody.innerText = '';
- }
-
- // Display component stack
- errorComponentStack.innerText = componentStack;
-
- // Display the call stack
- // Since we already displayed the message, strip it, and the first Error: line.
- errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1];
-
- // Display the cause, if available
- if (error.cause) {
- errorCauseMessage.innerText = error.cause.message;
- errorCauseStack.innerText = error.cause.stack;
- errorCause.classList.remove('hidden');
- } else {
- errorCause.classList.add('hidden');
- }
- // Display the close button, if dismissible
- if (dismissable) {
- errorNotDismissible.classList.add('hidden');
- errorClose.classList.remove("hidden");
- } else {
- errorNotDismissible.classList.remove('hidden');
- errorClose.classList.add("hidden");
- }
-
- // Show the dialog
- errorDialog.classList.remove("hidden");
-}
-
-export function reportCaughtError({error, cause, componentStack}) {
- reportError({ title: "Caught Error", error, componentStack, dismissable: true});
-}
-
-export function reportUncaughtError({error, cause, componentStack}) {
- reportError({ title: "Uncaught Error", error, componentStack, dismissable: false });
-}
-
-export function reportRecoverableError({error, cause, componentStack}) {
- reportError({ title: "Recoverable Error", error, componentStack, dismissable: true });
-}
-```
-
-```js src/index.js active
-import { createRoot } from "react-dom/client";
-import App from "./App.js";
-import {reportRecoverableError} from "./reportError";
-import "./styles.css";
-
-const container = document.getElementById("root");
-const root = createRoot(container, {
- onRecoverableError: (error, errorInfo) => {
- reportRecoverableError({
- error,
- cause: error.cause,
- componentStack: errorInfo.componentStack,
- });
- }
-});
-root.render();
-```
-
-```js src/App.js
-import { useState } from 'react';
-import { ErrorBoundary } from "react-error-boundary";
-
-// 🚩 Bug: Never do this. This will force an error.
-let errorThrown = false;
export default function App() {
+ const [triggerUncaughtError, settriggerUncaughtError] = useState(false);
+ const [triggerCaughtError, setTriggerCaughtError] = useState(false);
+
return (
<>
-
- {!errorThrown && }
- This component threw an error, but recovered during a second render.
- Since it recovered, no Error Boundary was shown, but onRecoverableError
was used to show an error dialog.
-
-
+
+ {triggerUncaughtError && }
+
+ {triggerCaughtError && (
+
+
+
+ )}
>
);
}
-
-function fallbackRender() {
- return (
-
-
Error Boundary
-
Something went wrong.
-
- );
-}
-
-function Throw({error}) {
- // Simulate an external value changing during concurrent render.
- errorThrown = true;
- foo.bar = 'baz';
-}
-```
-
-```json package.json hidden
-{
- "dependencies": {
- "react": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0",
- "react-error-boundary": "4.0.3"
- },
- "main": "/index.js"
-}
```
-
----
## Troubleshooting {/*troubleshooting*/}
### I've created a root, but nothing is displayed {/*ive-created-a-root-but-nothing-is-displayed*/}
diff --git a/src/content/reference/react-dom/client/hydrateRoot.md b/src/content/reference/react-dom/client/hydrateRoot.md
index cc30ce22c1..99190b03a7 100644
--- a/src/content/reference/react-dom/client/hydrateRoot.md
+++ b/src/content/reference/react-dom/client/hydrateRoot.md
@@ -41,8 +41,8 @@ React will attach to the HTML that exists inside the `domNode`, and take over ma
* **optional** `options`: An object with options for this React root.
- * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`.
- * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown and an `errorInfo` object containing the `componentStack`.
+ * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`.
+ * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown and an `errorInfo` object containing the `componentStack`.
* **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with the `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`.
* **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page. Must be the same prefix as used on the server.
@@ -99,7 +99,7 @@ An app fully built with React will usually not have any calls to `root.unmount`.
This is mostly useful if your React root's DOM node (or any of its ancestors) may get removed from the DOM by some other code. For example, imagine a jQuery tab panel that removes inactive tabs from the DOM. If a tab gets removed, everything inside it (including the React roots inside) would get removed from the DOM as well. You need to tell React to "stop" managing the removed root's content by calling `root.unmount`. Otherwise, the components inside the removed root won't clean up and free up resources like subscriptions.
-Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree.
+Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree.
#### Parameters {/*root-unmount-parameters*/}
@@ -270,7 +270,7 @@ export default function App() {
-This only works one level deep, and is intended to be an escape hatch. Don’t overuse it. Unless it’s text content, React still won’t attempt to patch it up, so it may remain inconsistent until future updates.
+This only works one level deep, and is intended to be an escape hatch. Don’t overuse it. React will **not** attempt to patch mismatched text content.
---
@@ -374,578 +374,125 @@ export default function App({counter}) {
It is uncommon to call [`root.render`](#root-render) on a hydrated root. Usually, you'll [update state](/reference/react/useState) inside one of the components instead.
-### Show a dialog for uncaught errors {/*show-a-dialog-for-uncaught-errors*/}
+### Error logging in production {/*error-logging-in-production*/}
-
+By default, React will log all errors to the console. To implement your own error reporting, you can provide the optional error handler root options `onUncaughtError`, `onCaughtError` and `onRecoverableError`:
-`onUncaughtError` is only available in the latest React Canary release.
-
-
-
-By default, React will log all uncaught errors to the console. To implement your own error reporting, you can provide the optional `onUncaughtError` root option:
-
-```js [[1, 7, "onUncaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack"]]
-import { hydrateRoot } from 'react-dom/client';
+```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack", 15]]
+import { hydrateRoot } from "react-dom/client";
+import { reportCaughtError } from "./reportError";
-const root = hydrateRoot(
- document.getElementById('root'),
- ,
- {
- onUncaughtError: (error, errorInfo) => {
- console.error(
- 'Uncaught error',
+const container = document.getElementById("root");
+const root = hydrateRoot(container, {
+ onCaughtError: (error, errorInfo) => {
+ if (error.message !== "Known error") {
+ reportCaughtError({
error,
- errorInfo.componentStack
- );
+ componentStack: errorInfo.componentStack,
+ });
}
- }
-);
-root.render();
+ },
+});
```
-The onUncaughtError option is a function called with two arguments:
+The onCaughtError option is a function called with two arguments:
1. The error that was thrown.
2. An errorInfo object that contains the componentStack of the error.
-You can use the `onUncaughtError` root option to display error dialogs:
+Together with `onUncaughtError` and `onRecoverableError`, you can implement your own error reporting system:
-```html index.html hidden
-
-
-
- My app
-
-
-
-
-
-
-
-
-
-
-
-
This error occurred at:
-
-
Call stack:
-
-
-
-
This error is not dismissible.
-
-
-This error shows the error dialog:
-
-
-```
-
-```css src/styles.css active
-label, button { display: block; margin-bottom: 20px; }
-html, body { min-height: 300px; }
-
-#error-dialog {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: white;
- padding: 15px;
- opacity: 0.9;
- text-wrap: wrap;
- overflow: scroll;
-}
-
-.text-red {
- color: red;
-}
-
-.-mb-20 {
- margin-bottom: -20px;
-}
-
-.mb-0 {
- margin-bottom: 0;
-}
-
-.mb-10 {
- margin-bottom: 10px;
-}
-
-pre {
- text-wrap: wrap;
-}
-
-pre.nowrap {
- text-wrap: nowrap;
-}
-
-.hidden {
- display: none;
+```js src/reportError.js
+function reportError({ type, error, errorInfo }) {
+ // The specific implementation is up to you.
+ // `console.error()` is only used for demonstration purposes.
+ console.error(type, error, "Component Stack: ");
+ console.error("Component Stack: ", errorInfo.componentStack);
}
-```
-```js src/reportError.js hidden
-function reportError({ title, error, componentStack, dismissable }) {
- const errorDialog = document.getElementById("error-dialog");
- const errorTitle = document.getElementById("error-title");
- const errorMessage = document.getElementById("error-message");
- const errorBody = document.getElementById("error-body");
- const errorComponentStack = document.getElementById("error-component-stack");
- const errorStack = document.getElementById("error-stack");
- const errorClose = document.getElementById("error-close");
- const errorCause = document.getElementById("error-cause");
- const errorCauseMessage = document.getElementById("error-cause-message");
- const errorCauseStack = document.getElementById("error-cause-stack");
- const errorNotDismissible = document.getElementById("error-not-dismissible");
-
- // Set the title
- errorTitle.innerText = title;
-
- // Display error message and body
- const [heading, body] = error.message.split(/\n(.*)/s);
- errorMessage.innerText = heading;
- if (body) {
- errorBody.innerText = body;
- } else {
- errorBody.innerText = '';
+export function onCaughtErrorProd(error, errorInfo) {
+ if (error.message !== "Known error") {
+ reportError({ type: "Caught", error, errorInfo });
}
-
- // Display component stack
- errorComponentStack.innerText = componentStack;
-
- // Display the call stack
- // Since we already displayed the message, strip it, and the first Error: line.
- errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1];
-
- // Display the cause, if available
- if (error.cause) {
- errorCauseMessage.innerText = error.cause.message;
- errorCauseStack.innerText = error.cause.stack;
- errorCause.classList.remove('hidden');
- } else {
- errorCause.classList.add('hidden');
- }
- // Display the close button, if dismissible
- if (dismissable) {
- errorNotDismissible.classList.add('hidden');
- errorClose.classList.remove("hidden");
- } else {
- errorNotDismissible.classList.remove('hidden');
- errorClose.classList.add("hidden");
- }
-
- // Show the dialog
- errorDialog.classList.remove("hidden");
-}
-
-export function reportCaughtError({error, cause, componentStack}) {
- reportError({ title: "Caught Error", error, componentStack, dismissable: true});
}
-export function reportUncaughtError({error, cause, componentStack}) {
- reportError({ title: "Uncaught Error", error, componentStack, dismissable: false });
+export function onUncaughtErrorProd(error, errorInfo) {
+ reportError({ type: "Uncaught", error, errorInfo });
}
-export function reportRecoverableError({error, cause, componentStack}) {
- reportError({ title: "Recoverable Error", error, componentStack, dismissable: true });
+export function onRecoverableErrorProd(error, errorInfo) {
+ reportError({ type: "Recoverable", error, errorInfo });
}
```
```js src/index.js active
import { hydrateRoot } from "react-dom/client";
import App from "./App.js";
-import {reportUncaughtError} from "./reportError";
-import "./styles.css";
-import {renderToString} from 'react-dom/server';
+import {
+ onCaughtErrorProd,
+ onRecoverableErrorProd,
+ onUncaughtErrorProd,
+} from "./reportError";
const container = document.getElementById("root");
-const root = hydrateRoot(container, , {
- onUncaughtError: (error, errorInfo) => {
- if (error.message !== 'Known error') {
- reportUncaughtError({
- error,
- componentStack: errorInfo.componentStack
- });
- }
- }
+hydrateRoot(container, , {
+ // Keep in mind to remove these options in development to leverage
+ // React's default handlers or implement your own overlay for development.
+ // The handlers are only specfied unconditionally here for demonstration purposes.
+ onCaughtError: onCaughtErrorProd,
+ onRecoverableError: onRecoverableErrorProd,
+ onUncaughtError: onUncaughtErrorProd,
});
```
```js src/App.js
-import { useState } from 'react';
+import { Component, useState } from "react";
-export default function App() {
- const [throwError, setThrowError] = useState(false);
-
- if (throwError) {
- foo.bar = 'baz';
- }
-
- return (
-
- This error shows the error dialog:
-
-
- );
+function Boom() {
+ foo.bar = "baz";
}
-```
-```json package.json hidden
-{
- "dependencies": {
- "react": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0"
- },
- "main": "/index.js"
-}
-```
-
-
-
-
-### Displaying Error Boundary errors {/*displaying-error-boundary-errors*/}
-
-
+class ErrorBoundary extends Component {
+ state = { hasError: false };
-`onCaughtError` is only available in the latest React Canary release.
-
-
-
-By default, React will log all errors caught by an Error Boundary to `console.error`. To override this behavior, you can provide the optional `onCaughtError` root option for errors caught by an [Error Boundary](/reference/react/Component#catching-rendering-errors-with-an-error-boundary):
-
-```js [[1, 7, "onCaughtError"], [2, 7, "error", 1], [3, 7, "errorInfo"], [4, 11, "componentStack"]]
-import { hydrateRoot } from 'react-dom/client';
-
-const root = hydrateRoot(
- document.getElementById('root'),
- ,
- {
- onCaughtError: (error, errorInfo) => {
- console.error(
- 'Caught error',
- error,
- errorInfo.componentStack
- );
- }
+ static getDerivedStateFromError(error) {
+ return { hasError: true };
}
-);
-root.render();
-```
-
-The onCaughtError option is a function called with two arguments:
-
-1. The error that was caught by the boundary.
-2. An errorInfo object that contains the componentStack of the error.
-You can use the `onCaughtError` root option to display error dialogs or filter known errors from logging:
-
-
-
-```html index.html hidden
-
-
-
- My app
-
-
-
-
-
-
-
-
-
-
-
-
This error occurred at:
-
-
Call stack:
-
-
-
-
This error is not dismissible.
-
-
-This error will not show the error dialog:This error will show the error dialog:
-
-
-```
-
-```css src/styles.css active
-label, button { display: block; margin-bottom: 20px; }
-html, body { min-height: 300px; }
-
-#error-dialog {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: white;
- padding: 15px;
- opacity: 0.9;
- text-wrap: wrap;
- overflow: scroll;
-}
-
-.text-red {
- color: red;
-}
-
-.-mb-20 {
- margin-bottom: -20px;
-}
-
-.mb-0 {
- margin-bottom: 0;
-}
-
-.mb-10 {
- margin-bottom: 10px;
-}
-
-pre {
- text-wrap: wrap;
-}
-
-pre.nowrap {
- text-wrap: nowrap;
-}
-
-.hidden {
- display: none;
-}
-```
-
-```js src/reportError.js hidden
-function reportError({ title, error, componentStack, dismissable }) {
- const errorDialog = document.getElementById("error-dialog");
- const errorTitle = document.getElementById("error-title");
- const errorMessage = document.getElementById("error-message");
- const errorBody = document.getElementById("error-body");
- const errorComponentStack = document.getElementById("error-component-stack");
- const errorStack = document.getElementById("error-stack");
- const errorClose = document.getElementById("error-close");
- const errorCause = document.getElementById("error-cause");
- const errorCauseMessage = document.getElementById("error-cause-message");
- const errorCauseStack = document.getElementById("error-cause-stack");
- const errorNotDismissible = document.getElementById("error-not-dismissible");
-
- // Set the title
- errorTitle.innerText = title;
-
- // Display error message and body
- const [heading, body] = error.message.split(/\n(.*)/s);
- errorMessage.innerText = heading;
- if (body) {
- errorBody.innerText = body;
- } else {
- errorBody.innerText = '';
- }
-
- // Display component stack
- errorComponentStack.innerText = componentStack;
-
- // Display the call stack
- // Since we already displayed the message, strip it, and the first Error: line.
- errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1];
-
- // Display the cause, if available
- if (error.cause) {
- errorCauseMessage.innerText = error.cause.message;
- errorCauseStack.innerText = error.cause.stack;
- errorCause.classList.remove('hidden');
- } else {
- errorCause.classList.add('hidden');
- }
- // Display the close button, if dismissible
- if (dismissable) {
- errorNotDismissible.classList.add('hidden');
- errorClose.classList.remove("hidden");
- } else {
- errorNotDismissible.classList.remove('hidden');
- errorClose.classList.add("hidden");
- }
-
- // Show the dialog
- errorDialog.classList.remove("hidden");
-}
-
-export function reportCaughtError({error, cause, componentStack}) {
- reportError({ title: "Caught Error", error, componentStack, dismissable: true});
-}
-
-export function reportUncaughtError({error, cause, componentStack}) {
- reportError({ title: "Uncaught Error", error, componentStack, dismissable: false });
-}
-
-export function reportRecoverableError({error, cause, componentStack}) {
- reportError({ title: "Recoverable Error", error, componentStack, dismissable: true });
-}
-```
-
-```js src/index.js active
-import { hydrateRoot } from "react-dom/client";
-import App from "./App.js";
-import {reportCaughtError} from "./reportError";
-import "./styles.css";
-
-const container = document.getElementById("root");
-const root = hydrateRoot(container, , {
- onCaughtError: (error, errorInfo) => {
- if (error.message !== 'Known error') {
- reportCaughtError({
- error,
- componentStack: errorInfo.componentStack
- });
+ render() {
+ if (this.state.hasError) {
+ return Something went wrong.
;
}
+ return this.props.children;
}
-});
-```
-
-```js src/App.js
-import { useState } from 'react';
-import { ErrorBoundary } from "react-error-boundary";
+}
export default function App() {
- const [error, setError] = useState(null);
-
- function handleUnknown() {
- setError("unknown");
- }
+ const [triggerUncaughtError, settriggerUncaughtError] = useState(false);
+ const [triggerCaughtError, setTriggerCaughtError] = useState(false);
- function handleKnown() {
- setError("known");
- }
-
return (
<>
- {
- setError(null);
- }}
- >
- {error != null && }
- This error will not show the error dialog:
-
- This error will show the error dialog:
-
-
-
+
+ {triggerUncaughtError && }
+
+ {triggerCaughtError && (
+
+
+
+ )}
>
);
}
-
-function fallbackRender({ resetErrorBoundary }) {
- return (
-
-
Error Boundary
-
Something went wrong.
-
-
- );
-}
-
-function Throw({error}) {
- if (error === "known") {
- throw new Error('Known error')
- } else {
- foo.bar = 'baz';
- }
-}
-```
-
-```json package.json hidden
-{
- "dependencies": {
- "react": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0",
- "react-error-boundary": "4.0.3"
- },
- "main": "/index.js"
-}
```
-
-
-### Show a dialog for recoverable hydration mismatch errors {/*show-a-dialog-for-recoverable-hydration-mismatch-errors*/}
-
-When React encounters a hydration mismatch, it will automatically attempt to recover by rendering on the client. By default, React will log hydration mismatch errors to `console.error`. To override this behavior, you can provide the optional `onRecoverableError` root option:
-
-```js [[1, 7, "onRecoverableError"], [2, 7, "error", 1], [3, 11, "error.cause", 1], [4, 7, "errorInfo"], [5, 12, "componentStack"]]
-import { hydrateRoot } from 'react-dom/client';
-
-const root = hydrateRoot(
- document.getElementById('root'),
- ,
- {
- onRecoverableError: (error, errorInfo) => {
- console.error(
- 'Caught error',
- error,
- error.cause,
- errorInfo.componentStack
- );
- }
- }
-);
-```
-
-The onRecoverableError option is a function called with two arguments:
-
-1. The error React throws. Some errors may include the original cause as error.cause.
-2. An errorInfo object that contains the componentStack of the error.
-
-You can use the `onRecoverableError` root option to display error dialogs for hydration mismatches:
-
-
-
-```html index.html hidden
+```html public/index.html hidden
@@ -953,226 +500,12 @@ You can use the `onRecoverableError` root option to display error dialogs for hy
-
-
-
-
-
-
-
-
-
This error occurred at:
-
-
Call stack:
-
-
-
-
This error is not dismissible.
-
-
-Server
+Server content before hydration.
```
-
-```css src/styles.css active
-label, button { display: block; margin-bottom: 20px; }
-html, body { min-height: 300px; }
-
-#error-dialog {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: white;
- padding: 15px;
- opacity: 0.9;
- text-wrap: wrap;
- overflow: scroll;
-}
-
-.text-red {
- color: red;
-}
-
-.-mb-20 {
- margin-bottom: -20px;
-}
-
-.mb-0 {
- margin-bottom: 0;
-}
-
-.mb-10 {
- margin-bottom: 10px;
-}
-
-pre {
- text-wrap: wrap;
-}
-
-pre.nowrap {
- text-wrap: nowrap;
-}
-
-.hidden {
- display: none;
-}
-```
-
-```js src/reportError.js hidden
-function reportError({ title, error, componentStack, dismissable }) {
- const errorDialog = document.getElementById("error-dialog");
- const errorTitle = document.getElementById("error-title");
- const errorMessage = document.getElementById("error-message");
- const errorBody = document.getElementById("error-body");
- const errorComponentStack = document.getElementById("error-component-stack");
- const errorStack = document.getElementById("error-stack");
- const errorClose = document.getElementById("error-close");
- const errorCause = document.getElementById("error-cause");
- const errorCauseMessage = document.getElementById("error-cause-message");
- const errorCauseStack = document.getElementById("error-cause-stack");
- const errorNotDismissible = document.getElementById("error-not-dismissible");
-
- // Set the title
- errorTitle.innerText = title;
-
- // Display error message and body
- const [heading, body] = error.message.split(/\n(.*)/s);
- errorMessage.innerText = heading;
- if (body) {
- errorBody.innerText = body;
- } else {
- errorBody.innerText = '';
- }
-
- // Display component stack
- errorComponentStack.innerText = componentStack;
-
- // Display the call stack
- // Since we already displayed the message, strip it, and the first Error: line.
- errorStack.innerText = error.stack.replace(error.message, '').split(/\n(.*)/s)[1];
-
- // Display the cause, if available
- if (error.cause) {
- errorCauseMessage.innerText = error.cause.message;
- errorCauseStack.innerText = error.cause.stack;
- errorCause.classList.remove('hidden');
- } else {
- errorCause.classList.add('hidden');
- }
- // Display the close button, if dismissible
- if (dismissable) {
- errorNotDismissible.classList.add('hidden');
- errorClose.classList.remove("hidden");
- } else {
- errorNotDismissible.classList.remove('hidden');
- errorClose.classList.add("hidden");
- }
-
- // Show the dialog
- errorDialog.classList.remove("hidden");
-}
-
-export function reportCaughtError({error, cause, componentStack}) {
- reportError({ title: "Caught Error", error, componentStack, dismissable: true});
-}
-
-export function reportUncaughtError({error, cause, componentStack}) {
- reportError({ title: "Uncaught Error", error, componentStack, dismissable: false });
-}
-
-export function reportRecoverableError({error, cause, componentStack}) {
- reportError({ title: "Recoverable Error", error, componentStack, dismissable: true });
-}
-```
-
-```js src/index.js active
-import { hydrateRoot } from "react-dom/client";
-import App from "./App.js";
-import {reportRecoverableError} from "./reportError";
-import "./styles.css";
-
-const container = document.getElementById("root");
-const root = hydrateRoot(container, , {
- onRecoverableError: (error, errorInfo) => {
- reportRecoverableError({
- error,
- cause: error.cause,
- componentStack: errorInfo.componentStack
- });
- }
-});
-```
-
-```js src/App.js
-import { useState } from 'react';
-import { ErrorBoundary } from "react-error-boundary";
-
-export default function App() {
- const [error, setError] = useState(null);
-
- function handleUnknown() {
- setError("unknown");
- }
-
- function handleKnown() {
- setError("known");
- }
-
- return (
- {typeof window !== 'undefined' ? 'Client' : 'Server'}
- );
-}
-
-function fallbackRender({ resetErrorBoundary }) {
- return (
-
-
Error Boundary
-
Something went wrong.
-
-
- );
-}
-
-function Throw({error}) {
- if (error === "known") {
- throw new Error('Known error')
- } else {
- foo.bar = 'baz';
- }
-}
-```
-
-```json package.json hidden
-{
- "dependencies": {
- "react": "canary",
- "react-dom": "canary",
- "react-scripts": "^5.0.0",
- "react-error-boundary": "4.0.3"
- },
- "main": "/index.js"
-}
-```
-
## Troubleshooting {/*troubleshooting*/}
diff --git a/src/content/reference/react-dom/components/common.md b/src/content/reference/react-dom/components/common.md
index 62ee08139d..9d15332139 100644
--- a/src/content/reference/react-dom/components/common.md
+++ b/src/content/reference/react-dom/components/common.md
@@ -246,43 +246,41 @@ These events fire for resources like [`