Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

what's the difference between getDerivedStateFromError and componentDidCatch

What I understood from here:

componentDidCatch:

  • is called always in the browser
  • is called during the "commit phase" when the DOM has already been updated
  • should be used for something like error's reporting

getDerivedStateFromError:

  • is also called during server-side-rendering
  • is called in "render phase" when the DOM has not yet been updated
  • should be used for rendering a fallback UI

Still, I'm bit confused about some things:

  1. are they both catching the same type of errors? or each lifecycle will catch the different error?
  2. should I always use both (in the same "error-catching" component possibly)?
  3. "using componentDidCatch for error recovery is not optimal because it forces the fallback UI to always render synchronously" what's wrong with that?
like image 902
Tomasz Mularczyk Avatar asked Oct 24 '18 07:10

Tomasz Mularczyk


People also ask

When should I use componentDidCatch?

The componentDidCatch() method is invoked if some error occurs during the rendering phase of any lifecycle methods or any children components. This method is used to implement the Error Boundaries for the React application.

Is getDerivedStateFromError a lifecycle method?

static getDerivedStateFromError()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.

What is the difference between try catch block and error boundaries?

catch deals with imperative code while error boundaries*deal with declarative code. Imperative programming is how you do something and declarative programming is what you do. With error boundary, if there is an error, you can trigger a fallback UI; whereas, with try… catch, you can catch errors in your code.

What is the advantage of an error boundary?

Error boundaries do not catch errors inside event handlers. React doesn't need error boundaries to recover from errors in event handlers. Unlike the render method and lifecycle methods, the event handlers don't happen during rendering. So if they throw, React still knows what to display on the screen.


2 Answers

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.

like image 105
Estus Flask Avatar answered Sep 23 '22 22:09

Estus Flask


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 then componentDidCatch (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

like image 45
Shubham Khatri Avatar answered Sep 21 '22 22:09

Shubham Khatri