User friendly errors with React error boundaries and fallback components

If we want to prevent our UI from crashing on errors and also have a fallback UI to show this errors in a friendly manner, we can use React error boundary components that wraps around critical parts of our app and catches JavaScript errors anywhere in …


This content originally appeared on DEV Community and was authored by Leandro Coelho

If we want to prevent our UI from crashing on errors and also have a fallback UI to show this errors in a friendly manner, we can use React error boundary components that wraps around critical parts of our app and catches JavaScript errors anywhere in it's child component tree.

Complete code example with typescript here.

Creating a custom error boundary component

Error boundaries are created as class components with access to two special lifecycle methods:

  • static getDerivedStateFromError() which updates it's state to show the fallback UI.
  • componentDidCatch() used to log error information.
class ErrorBoundary extends React.Component {
  state: State = {error: null}

  static getDerivedStateFromError(error) {
    return {error}
  }

  componentDidCatch(error, errorInfo) {
    logErrorToMyService(error, errorInfo);
  }

  render() {
    const {error} = this.state
    if (error) {
      return <this.props.FallbackComponent error={error} />
    }
    return this.props.children
  }
}

In this example we are passing a FallbackComponent to be rendered if our ErrorBoundary catches an error and we are logging the error to a external service.

To use the ErrorBoundary component in our application we just need to wrap it around a component that might come across some errors. In this example I wrapped a component that fetches data from an API and passed a fallback component that shows an error message if something goes wrong:

<ErrorBoundary
  // use key as a workaround for resetting the errorboundary state
  key={circuitName}
  FallbackComponent={CircuitErrorFallback}
>
  <CircuitContent />
</ErrorBoundary>
function CircuitErrorFallback({error}) {
  return (
    <div role="alert">
      <h3>Something went wrong...</h3>
      <p>{error.message}</p>
    </div>
  )
}

The <CircuitContent /> component will throw an error if something goes wrong with our API call:

function CircuitContent({circuitName}) {
  const [state, setState] = useState<>({
    status: 'idle',
    circuit: {},
    error: null,
  })
  const {status, circuit, error} = state

  useEffect(() => {
    if (!circuitName) {
      return
    }
    setState(prevState => ({...prevState, status: 'pending'}))
    fetchCircuit(circuitName).then(
      circuit => {
        setState(prevState => ({...prevState, status: 'resolved', circuit}))
      },
      error => {
        setState(prevState => ({...prevState, status: 'rejected', error}))
      },
    )  
  }, [circuitName])

  if (status === 'idle') {
    return <CircuitIdle />
  } else if (status === 'pending') {
    return <CircuitLoading />
  } else if (status === 'rejected') {
    // throw error to be handled by error boundary
    throw error
  } else if (status === 'resolved') {
    return <CircuitDetails circuit={circuit} />
  }

  throw new Error('Something went really wrong.')
}

And ErrorBoundary will catch this error and render our fallback component:

Error fallback component

Using react-error-boundary

Creating our own error boundary component is pretty straight forward but we can also install react-error-boundary package on our app and use it's features for resetting our error boundary and restoring the state of our UI.

import {ErrorBoundary} from 'react-error-boundary'

<ErrorBoundary
  onReset={handleReset}
  resetKeys={[circuitName]}
  FallbackComponent={CircuitErrorFallback}
>
  <CircuitContent circuitName={circuitName} />
</ErrorBoundary>

Now we can extend our fallback component with a button for reset the errorboundary:

function CircuitErrorFallback({ error, resetErrorBoundary }) {
  return (
    <div role="alert">
      <h3>Something went wrong...</h3>
      <p>{error.message}</p>
      <button onClick={resetErrorBoundary}>
        Try again
      </button>
    </div>
  )
}

And the resulting error UI will look like this:

Extended error fallback component

Conclusion

We can wrap different parts of our applications with error boundaries to keep our interface interactive and prevent crashing. This can also benefit us during development stage while catching errors that could even get unnoticed by typescript.

Note on usage with Create React App:

CRA may display an overlay with error information in development mode even if error boundary catches the error. There are workarounds to change this behavior of Create React App but I think it's unecessary, since you can press 'esc' to close the overlay and this will not be shown in production build anyway.

Tip for handling error messages with Axios:

Axios will throw an error with a custom message like "The server responded with 404 status code." when an API call fails. You can use an axios interceptor to change this custom message to the actual error message in the API response body or even map it to something else:

const api = axios.create({baseURL: 'https://api.backend.com'})
api.interceptors.response.use(
  response => response,
  error => {
    if (error.response.data.message) {
      error.message = error.response.data.message
    }
    return Promise.reject(error)
  },
)

The idea for this post came from a lesson on the React hooks workshop from epicreact.dev. Thanks for reading!


This content originally appeared on DEV Community and was authored by Leandro Coelho


Print Share Comment Cite Upload Translate Updates
APA

Leandro Coelho | Sciencx (2021-08-17T20:03:36+00:00) User friendly errors with React error boundaries and fallback components. Retrieved from https://www.scien.cx/2021/08/17/user-friendly-errors-with-react-error-boundaries-and-fallback-components/

MLA
" » User friendly errors with React error boundaries and fallback components." Leandro Coelho | Sciencx - Tuesday August 17, 2021, https://www.scien.cx/2021/08/17/user-friendly-errors-with-react-error-boundaries-and-fallback-components/
HARVARD
Leandro Coelho | Sciencx Tuesday August 17, 2021 » User friendly errors with React error boundaries and fallback components., viewed ,<https://www.scien.cx/2021/08/17/user-friendly-errors-with-react-error-boundaries-and-fallback-components/>
VANCOUVER
Leandro Coelho | Sciencx - » User friendly errors with React error boundaries and fallback components. [Internet]. [Accessed ]. Available from: https://www.scien.cx/2021/08/17/user-friendly-errors-with-react-error-boundaries-and-fallback-components/
CHICAGO
" » User friendly errors with React error boundaries and fallback components." Leandro Coelho | Sciencx - Accessed . https://www.scien.cx/2021/08/17/user-friendly-errors-with-react-error-boundaries-and-fallback-components/
IEEE
" » User friendly errors with React error boundaries and fallback components." Leandro Coelho | Sciencx [Online]. Available: https://www.scien.cx/2021/08/17/user-friendly-errors-with-react-error-boundaries-and-fallback-components/. [Accessed: ]
rf:citation
» User friendly errors with React error boundaries and fallback components | Leandro Coelho | Sciencx | https://www.scien.cx/2021/08/17/user-friendly-errors-with-react-error-boundaries-and-fallback-components/ |

Please log in to upload a file.




There are no updates yet.
Click the Upload button above to add an update.

You must be logged in to translate posts. Please log in or register.