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>Reading progress
0% read
In this module
Error Boundary
Suspense
Compound Component
Render prop
0%