Bayangin app banking — pas user lihat saldo, satu komponen <TransactionList> lempar error karena data corrupt. Tanpa error boundary, ENTIRE APP CRASH — white screen, user gak bisa logout, gak bisa lihat info lain. Dengan error boundary, error di-catch, fallback UI muncul ("Daftar transaksi error, coba refresh"), sisa app tetap jalan. Error Boundaries adalah komponen yang nge-catch JavaScript error di render tree komponen children-nya, prevent app crash total. WAJIB ada di production app — minimal di top level.
💡 Production must-have. Tiap React app yang serius punya minimum 1 error boundary di root. Library populer:
react-error-boundary— kasih hook + component pattern + reset functionality, cleaner dari class component manual. Lebih mudah di-test.
Class Component (Built-in)
class ErrorBoundary extends React.Component {
state = { hasError: false, error: null }
static getDerivedStateFromError(error) {
return { hasError: true, error }
}
componentDidCatch(error, info) {
console.error("Error caught:", error, info)
// Kirim ke service: Sentry.captureException(error)
}
render() {
if (this.state.hasError) {
return (
<div className="error-fallback">
<h2>Ada yang salah</h2>
<p>{this.state.error.message}</p>
<button onClick={() => this.setState({ hasError: false })}>
Coba Lagi
</button>
</div>
)
}
return this.props.children
}
}
// Pemakaian
<ErrorBoundary>
<App />
</ErrorBoundary>
Library: react-error-boundary (Recommended)
import { ErrorBoundary } from "react-error-boundary"
function ErrorFallback({ error, resetErrorBoundary }) {
return (
<div role="alert">
<p>Error: {error.message}</p>
<button onClick={resetErrorBoundary}>Coba Lagi</button>
</div>
)
}
<ErrorBoundary
FallbackComponent={ErrorFallback}
onError={(error, info) => Sentry.captureException(error)}
onReset={() => window.location.reload()}
>
<App />
</ErrorBoundary>
Granular Boundaries — Best Practice
function App() {
return (
<ErrorBoundary fallback={<AppErrorPage />}> {/* root catch */}
<Layout>
<Sidebar />
<ErrorBoundary fallback={<MainErrorPage />}> {/* main content area */}
<Routes>
<Route path="/transactions" element={
<ErrorBoundary fallback={<TransactionsError />}> {/* halaman tertentu */}
<Transactions />
</ErrorBoundary>
} />
</Routes>
</ErrorBoundary>
</Layout>
</ErrorBoundary>
)
}
Layered: error di Transactions cuma kena fallback Transactions, app + sidebar tetap jalan.
Apa yang TIDAK ditangkap
❌ Event handler — onClick={() => { throw new Error() }} lolos error boundary. Pakai try/catch manual.
❌ Async code — setTimeout(() => { throw err }, 100) lolos. Pakai try/catch di async function.
❌ Server-side rendering — error di SSR di-handle berbeda.
❌ Error di error boundary itu sendiri — error boundary gak self-heal, parent boundary yang nge-catch.
// Event handler — pakai try/catch
const handleClick = () => {
try {
riskyOp()
} catch (e) {
setError(e.message)
}
}
// Async — pakai try/catch
async function loadData() {
try {
const data = await fetch(...)
} catch (e) {
setError(e.message)
}
}
🎭 Analogi sehari-hari
Error Boundary itu kayak sekat tahan api di gedung tinggi. Pas ada kebakaran di lantai 5, sekat nyegah api naik ke lantai 6-50 — orang di lantai atas tetap aman, evacuation di lantai 5 doang. Tanpa sekat (no error boundary), satu kebakaran kecil = seluruh gedung kebakar (entire app crash). Granular boundaries = banyak sekat di lantai berbeda. Error di Transactions section = cuma section itu yang "kebakaran", Sidebar + Header + Footer tetap fungsional. Logging error juga otomatis (componentDidCatch / onError) = tahu error apa, di mana, kapan terjadi.
⚠️ Jebakan yang sering ditemui
- Cuma 1 boundary di root — error mana pun = full screen fallback. Pakai granular: per route, per section, per widget.
- Pikir error boundary nangkep async error — TIDAK.
useEffect+ fetch error = boundary skip. Set error state manual. - Pikir nangkep event handler error — TIDAK.
onClickerror = lolos. Pakaitry/catch. - Custom error boundary tanpa logging — error muncul di production, gak ada trace. Pakai Sentry/Bugsnag/Datadog.
- Reset boundary tanpa membersihkan state — user klik "coba lagi", error muncul lagi karena state belum di-reset. Pakai
keyprop atauonReset. - Lupa hook equivalent — gak ada
useErrorBoundarybuilt-in di React (per 2026). Libraryreact-error-boundarykasihuseErrorBoundary()hook untuk trigger error dari child. - Error boundary di Suspense fallback — error pas Suspense loading bisa nge-loop. Pikir struktur error vs loading state.
🎯 Tempat pasang error boundary?
- Root level (App) → catch-all fallback "Aplikasi error, refresh" (WAJIB)
- Per route page → fallback per halaman (page error gak crash navigation)
- Per data-heavy widget (chart, table, complex form) → fallback per widget
- Per critical section (auth, payment) → custom fallback dengan retry
- Around Suspense boundary → handle async loading + error
Aturan: minimal 1 di root + 1 per route. Tambah lebih granular di section yang prone error (data fetching, third-party widget).
TL;DR: Error Boundary = komponen yang nge-catch error di render children, tampilin fallback UI biar app gak crash total. Class component pattern (atau pakai library react-error-boundary). WAJIB ada di production app — minimum 1 di root. Granular: per route + per critical section. TIDAK nangkep: event handler error, async error, SSR error — pakai try/catch manual. Logging via componentDidCatch/onError ke Sentry/Bugsnag.