JSTAcademy
0 XP
Dashboard
Crash Courses
Error Boundaries & Patterns
10 min
PhD+200 XP
Crash Courses · PhD

Error Boundaries & Patterns

Handle errors gracefully and apply production React patterns.
10 min read+200 XP on completionCert: React Crash Course
Tap any word in the text below to start reading from there.

Error Boundaries & Production Patterns

Production React requires graceful error handling and patterns that scale across large codebases.

Error Boundary

import { Component, ErrorInfo } from 'react'

interface Props { children: React.ReactNode; fallback?: React.ReactNode }
interface State { hasError: boolean; error?: Error }

class ErrorBoundary extends Component<Props, State> {
  state: State = { hasError: false }

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

  componentDidCatch(error: Error, info: ErrorInfo) {
    console.error('Error caught:', error, info)
    // report to monitoring service
  }

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

// Usage
<ErrorBoundary fallback={<ErrorScreen />}>
  <RiskyComponent />
</ErrorBoundary>

Suspense + Lazy Loading

const HeavyChart = lazy(() => import('./HeavyChart'))

function Dashboard() {
  return (
    <ErrorBoundary>
      <Suspense fallback={<ChartSkeleton />}>
        <HeavyChart data={data} />
      </Suspense>
    </ErrorBoundary>
  )
}

Always wrap Suspense in an ErrorBoundary in production.

forwardRef

interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
  label: string
}

const Input = forwardRef<HTMLInputElement, InputProps>(
  ({ label, ...props }, ref) => (
    <div className="input-wrapper">
      <label>{label}</label>
      <input ref={ref} {...props} />
    </div>
  )
)

// Usage — parent can access the underlying input element
function Form() {
  const inputRef = useRef<HTMLInputElement>(null)
  return <Input label="Email" ref={inputRef} type="email" />
}

Compound Component Pattern

const TabsContext = createContext<{ active: string; set: (id: string) => void } | null>(null)

function Tabs({ children, defaultTab }: { children: React.ReactNode; defaultTab: string }) {
  const [active, setActive] = useState(defaultTab)
  return <TabsContext.Provider value={{ active, set: setActive }}>{children}</TabsContext.Provider>
}

Tabs.Tab = function Tab({ id, children }: { id: string; children: React.ReactNode }) {
  const ctx = useContext(TabsContext)!
  return (
    <button
      className={ctx.active === id ? 'active' : ''}
      onClick={() => ctx.set(id)}
    >{children}</button>
  )
}

// Usage
<Tabs defaultTab="overview">
  <Tabs.Tab id="overview">Overview</Tabs.Tab>
  <Tabs.Tab id="modules">Modules</Tabs.Tab>
</Tabs>
0%