-
Notifications
You must be signed in to change notification settings - Fork 7.8k
Add docs for getDerivedStateFromError [16.6] #1223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -81,8 +81,9 @@ This method is called when a component is being removed from the DOM: | |
|
||
#### Error Handling | ||
|
||
This method is called when there is an error during rendering, in a lifecycle method, or in the constructor of any child component. | ||
These methods are called when there is an error during rendering, in a lifecycle method, or in the constructor of any child component. | ||
|
||
- [`static getDerivedStateFromError()`](#getderivedstatefromerror) | ||
- [`componentDidCatch()`](#componentdidcatch) | ||
|
||
### Other APIs | ||
|
@@ -290,6 +291,7 @@ This method doesn't have access to the component instance. If you'd like, you ca | |
|
||
Note that this method is fired on *every* render, regardless of the cause. This is in contrast to `UNSAFE_componentWillReceiveProps`, which only fires when the parent causes a re-render and not as a result of a local `setState`. | ||
|
||
* * * | ||
|
||
### `getSnapshotBeforeUpdate()` | ||
|
||
|
@@ -311,21 +313,110 @@ In the above examples, it is important to read the `scrollHeight` property in `g | |
|
||
* * * | ||
|
||
### Error boundaries | ||
|
||
[Error boundaries](/docs/error-boundaries.html) are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them. | ||
|
||
A class component becomes an error boundary if it defines either (or both) of the lifecycle methods `static getDerivedStateFromError()` or `componentDidCatch()`. Updating state from these lifecycles lets you capture an unhandled JavaScript error in the below tree and display a fallback UI. | ||
|
||
Only use error boundaries for recovering from unexpected exceptions; **don't try to use them for control flow.** | ||
|
||
For more details, see [*Error Handling in React 16*](/blog/2017/07/26/error-handling-in-react-16.html). | ||
|
||
> Note | ||
> | ||
> Error boundaries only catch errors in the components **below** them in the tree. An error boundary can’t catch an error within itself. | ||
|
||
### `static getDerivedStateFromError()` | ||
```javascript | ||
static getDerivedStateFromError(error) | ||
``` | ||
|
||
This lifecycle is invoked after an error has been thrown by a descendant component. | ||
It receives the error that was thrown as a parameter and should return a value to update state. | ||
|
||
```js{7-10,13-16} | ||
class ErrorBoundary extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { hasError: false }; | ||
} | ||
|
||
static getDerivedStateFromError(error) { | ||
// Update state so the next render will show the fallback UI. | ||
return { hasError: true }; | ||
} | ||
|
||
render() { | ||
if (this.state.hasError) { | ||
// You can render any custom fallback UI | ||
return <h1>Something went wrong.</h1>; | ||
} | ||
|
||
return this.props.children; | ||
} | ||
} | ||
``` | ||
|
||
> Note | ||
> | ||
> `getDerivedStateFromError()` is called during the "render" phase, so side-effects are not permitted. | ||
For those use cases, use `componentDidCatch()` instead. | ||
|
||
* * * | ||
|
||
### `componentDidCatch()` | ||
|
||
```javascript | ||
componentDidCatch(error, info) | ||
``` | ||
|
||
[Error boundaries](/docs/error-boundaries.html) are React components that catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI instead of the component tree that crashed. Error boundaries catch errors during rendering, in lifecycle methods, and in constructors of the whole tree below them. | ||
This lifecycle is invoked after an error has been thrown by a descendant component. | ||
It receives two parameters: | ||
|
||
A class component becomes an error boundary if it defines this lifecycle method. Calling `setState()` in it lets you capture an unhandled JavaScript error in the below tree and display a fallback UI. Only use error boundaries for recovering from unexpected exceptions; don't try to use them for control flow. | ||
1. `error` - The error that was thrown. | ||
2. `info` - An object with a `componentStack` key containing [information about which component threw the error](/docs/error-boundaries.html#component-stack-traces). | ||
|
||
For more details, see [*Error Handling in React 16*](/blog/2017/07/26/error-handling-in-react-16.html). | ||
|
||
`componentDidCatch()` is called during the "commit" phase, so side-effects are permitted. | ||
It should be used for things like logging errors: | ||
|
||
```js{12-19} | ||
class ErrorBoundary extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.state = { hasError: false }; | ||
} | ||
|
||
static getDerivedStateFromError(error) { | ||
// Update state so the next render will show the fallback UI. | ||
return { hasError: true }; | ||
} | ||
|
||
componentDidCatch(error, info) { | ||
// Example "componentStack": | ||
// in ComponentThatThrows (created by App) | ||
// in ErrorBoundary (created by App) | ||
// in div (created by App) | ||
// in App | ||
logComponentStackToMyService(info.componentStack); | ||
} | ||
|
||
render() { | ||
if (this.state.hasError) { | ||
// You can render any custom fallback UI | ||
return <h1>Something went wrong.</h1>; | ||
} | ||
|
||
return this.props.children; | ||
} | ||
} | ||
``` | ||
|
||
> Note | ||
> | ||
> Error boundaries only catch errors in the components **below** them in the tree. An error boundary can’t catch an error within itself. | ||
> In the event of an error, you can render a fallback UI with `componentDidCatch()` by calling `setState`, but this will be deprecated in a future release. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we move this explanation earlier, and explain that defining There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah, I was on the fence about this. It felt a little odd to say this in the docs before we've actually officially deprecated the method. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree, but if we're going to have the two methods we should probably explain why There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we do explain why, by saying one is used for rendering fallback UI and the other is used for e.g. logging. I was just a bit reluctant to say "and the other will also be deprecated" until we've actually done that. It also feels a bit awkward to move the warning any earlier because then it would disconnect the code example. I don't feel strongly about this. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've made the other two edits. I'm not sure what to do with this one. If you have concrete wording or placement suggestions though I'm happy to make them. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok maybe if you change the other sentence above then it will fix my concern There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what are advantages of separating those 2 things? i understand the part about side effects being allowed in one and not in the other one, but There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a great question! 😄Hopefully documentation will be sufficient to avoid confusion for newcomers, but it's a valid concern. My understanding of this is that there are a couple of motivating factors: It works with server-side rendering. Render phase recovery is safer. The story for error recovery via It's more optimal for async rendering. Because state-updates from commit phase lifecycles are always synchronous, and because There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I ofc dont judge the chosen APIs too harshly as Im not competent enough to do that, not knowing all intricacies of the implementation. Just commenting from the user's perspective. And thanks for the explanation! Just want to comment a little bit on the given arguments
|
||
> Use `static getDerivedStateFromError()` to handle fallback rendering instead. | ||
|
||
* * * | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok yeah this looks better