← Docs
Recipe

React error boundary patterns

Catch render-phase errors gracefully without unmounting the entire tree.

Class component boundary

class ErrorBoundary extends React.Component {
  state = { hasError: false, error: null };

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

  componentDidCatch(error, info) {
    console.error("Boundary caught:", error, info);
  }

  render() {
    if (this.state.hasError) {
      return this.props.fallback ?? <h2>Something went wrong.</h2>;
    }
    return this.props.children;
  }
}

Reset via key

function ResettableErrorBoundary({ children, fallback }) {
  const [errorKey, setErrorKey] = React.useState(0);

  return (
    <ErrorBoundary
      key={errorKey}
      fallback={
        <div>
          {fallback}
          <button onClick={() => setErrorKey(k => k + 1)}>
            Retry
          </button>
        </div>
      }
    >
      {children}
    </ErrorBoundary>
  );
}

Event handler errors

Boundaries do not catch errors inside event handlers. Wrap with try/catch and set state.

function SafeButton() {
  const [error, setError] = React.useState(null);

  const handleClick = async () => {
    try {
      await riskyOperation();
    } catch (e) {
      setError(e.message);
    }
  };

  if (error) return <p className="text-red-400">{error}</p>;
  return <button onClick={handleClick}>Run</button>;
}

Tip: Place boundaries around subtrees that depend on external data or third-party components. Keep fallbacks lightweight — avoid cascading failures.