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!
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).
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.
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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With