Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Error Boundary in React: why does 'throw new Error('some message')' fail and 'throw errorObj' work?

I'm learning Error Boundaries in React. I think I've got a good basic understanding but am having trouble implementing them for asynchronous processes, such as loading data.

Let's say I have a simple component that, using React hooks, loads some data from a remote API. Since error boundaries won't work using asynchronous processes per se, instead of throwing an error in catch, this component stores the error in state and throws it on next re-render

// MovieDb.js
import axios from "axios"
import {useEffect,useState} from 'react'

export default (query) => {

  const [movies, setMovies] = useState([])
  const [error,setError] = useState(null)

  if (error) throw error

  useEffect(() => {
    const getData = async () => {
      try {
        const results = await axios.get('https://api.themoviedb.org/3/search/movie', {
          params: {
            api_key: 'somethingsomething',
            query
          }
        })
        setMovies(results.data.results)
      } catch (e) {
       setError(e)
      }
    }
    getData()
  }, [query])

  return movies

}

This component is used in my App:

// App.js
  function App() {

  const [query, setQuery] = useState('Lord of the Rings')

  const movies = MovieDb(query)
  return (
    <div className="App">
      <SearchInput onChange={e => setQuery(e.target.value)} defaultValue={query}/>
      {movies && movies.map(movie=> <div key={movie.id}>{movie.title}</div>) }
    </div>
  );
}

export default App;

My Error Boundary is very simple:

//Catch.js
import React, { Component } from 'react'

export default class Catch extends Component {
  state = { hasError: false ,error:''}

  static getDerivedStateFromError(error) {
    return { hasError: true,error }
  }

  render() {
    if (this.state.hasError) {

      return <h1>{`There was a problem: ${this.state.error.message}`}</h1>
    }

    return this.props.children
  }
}

This Catch component then wraps the App:

// index.js
ReactDOM.render(<Catch><App/></Catch>, document.getElementById('root'));

The Error Boundary seems to work when I throw an error inside MovieDb, such as when calling the API. However, when I change

 if (error) throw error

to

 if (error) throw new Error('some message')

or

 if (error) throw new Error(error.message)

the Error Boundary doesn't work and the app crashes. Why is this? I'm asking so that I can understand better what I'm doing, not just to make it work. Thanks for any help!

like image 848
Cerulean Avatar asked Jul 30 '19 14:07

Cerulean


People also ask

Why are there error boundaries in React?

Reason to Use: Suppose there is an error in JavaScript inside component then it used to corrupt React's internal state and cause it to emit cryptic errors. Error boundaries help in removing these errors and display a Fallback UI instead(Which means a display of an error that something broke in the code).

How are error boundaries handled in React?

Error boundaries 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.

How do you catch throw new error in React?

import { useState } from "react"; const App = () => { const [error, setError] = useState(Error()); const throwError = () => { throw Error("I'm an error"); }; const crash = () => { try { throwError(); } catch (e) { setError(e); console.

What happens when an error is not caught by error boundary?

Similarly to how the catch block works, if an error boundary fails trying to render the error message, the error will propagate to the closest error boundary above it. If errors thrown are not caught by any of the error boundaries, the whole component tree will be unmounted.


1 Answers

This is an artifact of the dev environment. You can see your actual UI by hitting "escape" or the "X" to dismiss the stack trace. This won't show up in production. I believe the react dev code looks at where the Exception was thrown and if it's in your code then you see the UI.

See: React still showing errors after catching with ErrorBoundary

like image 195
Josh Sacks Avatar answered Sep 27 '22 16:09

Josh Sacks