Error boundaries

Wrap regions in an ErrorBoundary so one error doesn't blank the page.

From frontend-patterns: “Error Boundary Pattern”.

Crash one widget

Type a note, then press Load bad data in each.

No boundaryBad

Boundary per widgetGood

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

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

  componentDidCatch(error, errorInfo) {
    console.error('Error boundary caught:', error, errorInfo)
  }

  render() {
    if (!this.state.hasError) return this.props.children
    return (
      <div className="error-fallback">
        <h2>Something went wrong</h2>
        <p>{this.state.error?.message}</p>
        <button onClick={() => this.setState({ hasError: false })}>Try again</button>
      </div>
    )
  }
}

Where the boundary goes

Pick a placement, then press Crash Revenue.

Boundary placement
Rendered4 of 4
Component treeReact
    // Coarse: any throw swaps the whole app for the fallback
    <ErrorBoundary>
      <App />
    </ErrorBoundary>
    
    // Fine: each independent region fails on its own
    function App() {
      return (
        <>
          <Header />
          <ErrorBoundary><Balance /></ErrorBoundary>
          <ErrorBoundary><Notes /></ErrorBoundary>
          <ErrorBoundary><Revenue /></ErrorBoundary>
        </>
      )
    }

    Try again, broken then fixed

    Tick Break the API, press Refresh, then recover.

    Reload-only fallbackBad

    Try again resets itGood

    // app/dashboard/error.tsx: the same boundary, per route segment
    'use client'
    
    export default function Error({ error, reset }) {
      return (
        <div>
          <p>{error.message}</p>
          <button onClick={() => reset()}>Try again</button>
        </div>
      )
    }

    Why it matters, pros and cons

    Why it matters

    Without a boundary, one render error unmounts the whole app. A boundary contains it.

    Pros

    • Siblings keep their state and work.
    • Try again recovers without a reload.
    • One place to report render errors.

    Cons

    • Misses event handler, timer and promise errors.
    • Class components only; no hook equivalent.
    • Too coarse or too fine both hide failures.