How can I make use of Error boundaries in functional React components?

ReactjsError Handling

Reactjs Problem Overview


I can make a class an error boundary in React by implementing componentDidCatch.

Is there a clean approach to making a functional component into an error boundary without converting it into a class?

Or is this a code smell?

Reactjs Solutions


Solution 1 - Reactjs

As of v16.2.0, there's no way to turn a functional component into an error boundary.

The React docs are clear about that, although you're free to reuse them as many times as you wish:

> The componentDidCatch() method works like a JavaScript catch {} block, but for components. Only class components can be error boundaries. In practice, most of the time you’ll want to declare an error boundary component once and use it throughout your application.

Also bear in mind that try/catch blocks won't work on all cases.
If a component deep in the hierarchy tries to updates and fails, the try/catch block in one of the parents won't work -- because it isn't necessarily updating together with the child.

Solution 2 - Reactjs

There is an implementation that can handle with non-existent functionalities for a functional component such as componentDidCatch and deriveStateFromError.

According to the author, it is based on React.memo().

> The proposed solution is greatly inspired by the new React.memo() API.

import Catch from "./functional-error-boundary"

type Props = {
  children: React.ReactNode
}

const MyErrorBoundary = Catch(function MyErrorBoundary(props: Props, error?: Error) {
  if (error) {
    return (
      <div className="error-screen">
        <h2>An error has occured</h2>
        <h4>{error.message}</h4>
      </div>
    )
  } else {
    return <React.Fragment>{props.children}</React.Fragment>
  }
})

reference and API here

Solution 3 - Reactjs

As mentioned already, the React team has not yet implemented a hook equivalent, and there are no published timelines for a hook implementation.

A few third party packages on npm implement error boundary hooks. I published react-use-error-boundary, attempting to recreate an API similar to useErrorBoundary from Preact:

import { withErrorBoundary, useErrorBoundary } from "react-use-error-boundary";

const App = withErrorBoundary(({ children }) => {
  const [error, resetError] = useErrorBoundary(
    // You can optionally log the error to an error reporting service
    (error, errorInfo) => logErrorToMyService(error, errorInfo)
  );

  if (error) {
    return (
      <div>
        <p>{error.message}</p>
        <button onClick={resetError}>Try again</button>
      </div>
    );
  }

  return <div>{children}</div>;
});

Solution 4 - Reactjs

Official React team not provided Error boundary support for functional component. We can achieve error boundary for functional component using npm package. https://www.npmjs.com/package/react-error-boundary

Solution 5 - Reactjs

What I have done is create custom class component and wrapped my functional/class component inside it where ever its required. This is how my custom class component looks like:

class ErrorBoundary extends React.Component {
  constructor(props) {
    super(props);
    this.state = {error: ""};
  }

  componentDidCatch(error) {
    this.setState({error: `${error.name}: ${error.message}`});
  }

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

And used it like this my functional/class components:

<ErrorBoundary key={uniqueKey}>
   <FuncationalOrChildComponent {...props} />
</ErrorBoundary>

PS: As usual the key property is very important as it will make sure to re-render the ErrorBoundary component if you have dynamic child elements.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDancrumbView Question on Stackoverflow
Solution 1 - ReactjsgustavohenkeView Answer on Stackoverflow
Solution 2 - ReactjsLuis FebroView Answer on Stackoverflow
Solution 3 - ReactjsTate ThurstonView Answer on Stackoverflow
Solution 4 - ReactjsSujitView Answer on Stackoverflow
Solution 5 - ReactjsDipakView Answer on Stackoverflow