what's the difference between getDerivedStateFromError and componentDidCatch
The statements in the question are mostly correct. Currently error boundaries aren't supported in SSR, getDerivedStateFromError
and componentDidCatch
don't affect server side.
are they both catching the same type of errors? or each lifecycle will catch the different error?
They are catching same errors but at different phases. This previously was possible with componentDidCatch
alone:
static getDerivedStateFromError() {
return { hasError: true };
}
and
componentDidCatch() {
this.setState({ hasError: true });
}
do the same thing, componentDidCatch
has no chances to be supported on server side until the support for asynchronous rendering will be added to ReactDOMServer
.
should I always use both (in the same "error-catching" component possibly)?
You can use both. An example from the documentation shows that:
class ErrorBoundary extends React.Component {
state = { hasError: false };
static getDerivedStateFromError(error) {
return { hasError: true };
}
componentDidCatch(error, info) {
logComponentStackToMyService(info.componentStack);
}
render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}
In this case responsibilities are divided between them. getDerivedStateFromError
does the only thing it is good for, i.e. updates the state if an error occurs, while componentDidCatch
provides side effects and can access this
component instance if needed.
"using componentDidCatch for error recovery is not optimal because it forces the fallback UI to always render synchronously" what's wrong with that?
New React releases are aimed at asynchronous rendering which is more efficient. As it was also mentioned in the comment, synchronous rendering is not a big concern for fallback UI because it can be considered edge case.
Both of these methods are called when there is an error during rendering, in a lifecycle method, or in the constructor of any child component. They can be used while implementing Error boundaries
According to the React docs
getDerivedStateFromError
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.
are they both catching the same type of errors? or each lifecycle will catch the different error?
Both of these lifecycle methods will catch the same errors, but the arguments to both of these components are different.
While getDerivedStateFromError
receives just the error as the arguments, componentDidCatch also receives the second parameter which is info, i.e An object with a componentStack key containing information about which component threw the error.
getDerivedStateFromError()
is called during the “render” phase, so side-effects are not permitted. For those use cases, use componentDidCatch()
instead. While componentDidCatch
can also be used to setState but this will be deprecated in future releases
componentDidCatch
should be used for sideEffects like logging errors
Also @Brian Vaughn
has elaborated more on their usage on the link that you provide
getDerivedStateFromError
works with server-side rendering. componentDidCatch is a commit phase lifecycle, but there is no commit phase on the server. getDerivedStateFromError is a render phase lifecycle, and so it can be used to enable error handling on the server.Render phase recovery is safer. The story for error recovery via
componentDidCatch
is a little janky, since it relies on an intermediate commit of "null" for everything below the component that errored. This might result in subsequent errors inside of any components higher up in the tree that implement componentDidMount or componentDidUpdate and just assume that their refs will be non-null (because they always are in the non-error case).
getDerivedStateFromError
doesn't force sync rendering. Because state-updates from commit phase lifecycles are always synchronous, and because componentDidCatch is called during the commit phase– using componentDidCatch for error recovery is not optimal because it forces the fallback UI to always render synchronously. (This is admittedly not a huge concern, since error recovery should be an edge case.)In the event of an error, your error boundary's
getDerivedStateFromError()
method will first be called (to update state), then the render() method (to actually render the fallback UI), and thencomponentDidCatch
(once the fallback UI has been committed to the DOM).If your error boundary defines other lifecycle methods (e.g. componentWillUpdate, componentDidUpdate) they will also get called, just like they would on any other render.
"using componentDidCatch for error recovery is not optimal because it forces the fallback UI to always render synchronously" what's wrong with that?
what it means is that , componentDidCatch is called after the render method which renders fallback UI and that might lead to more issues while getDerivedStateFromError
updates state before the render phase so that the correct fallback UI is rendered and no more errors are caused to the rendered components. Also the new releases aim at async rendering which might have issues with the current approach