Error Boundaries — React

Bayangin app banking — pas user lihat saldo, satu komponen lempar error karena data corrupt. Tanpa error boundary, ENTIRE APP CRASH — white screen, user gak…

Kalau satu komponen error waktu render dan gak ada yang menangkapnya, React membongkar seluruh tampilan app, dan layarnya jadi putih. Error boundary adalah komponen yang menangkap error dari komponen di dalamnya waktu render, lalu menampilkan tampilan cadangan (fallback UI) di tempat itu saja, sementara bagian app yang lain tetap jalan. Bayangin MCB, sakelar pengaman listrik per ruangan di rumah. Kalau ada korsleting di dapur, cuma MCB dapur yang turun dan lampu dapur mati, ruang tamu tetap terang. Tanpa MCB per ruangan, satu korsleting mematikan listrik seluruh rumah.

🧪 Tebakan cepat: di dalam ErrorBoundary ada tombol dengan onClick={() => { throw new Error("Gagal menyimpan") }}. Tombolnya diklik. Apakah fallback-nya muncul? Tebak dulu, jawabannya ada di bagian "Yang gak ditangkap".

Satu error, satu layar putih

function Profil({ user }) {
  return <p>Halo, {user.nama}</p>
}

function App() {
  const [user, setUser] = useState({ nama: "Budi" })
  return (
    <div>
      <Profil user={user} />
      <p>Saldo: Rp 250.000</p>
      <button onClick={() => setUser(null)}>Rusakkan data</button>
    </div>
  )
}

Klik "Rusakkan data": Profil render lagi dengan user berisi null, dan user.nama melempar error. Di Chrome pesannya TypeError: Cannot read properties of null (reading 'nama'). Gak ada yang menangkapnya, jadi React membuang seluruh tampilan App, termasuk saldo yang gak salah apa-apa.

Membuat ErrorBoundary

Error boundary harus ditulis sebagai class component: komponen yang dibuat dengan class, bukan function. Sampai sekarang belum ada hook bawaan React untuk ini.

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

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

  componentDidCatch(error, info) {
    console.log("Tertangkap:", error.message)
  }

  render() {
    if (this.state.hasError) {
      return <div id="fallback">Terjadi error</div>
    }
    return this.props.children
  }
}

function App() {
  // ... user, setUser seperti tadi
  return (
    <div>
      <ErrorBoundary>
        <Profil user={user} />
      </ErrorBoundary>
      <p>Saldo: Rp 250.000</p>
    </div>
  )
}
Kejadian hasError Yang tampil
Halaman dibuka false Halo, Budi dan Saldo: Rp 250.000
Klik "Rusakkan data" true Terjadi error dan Saldo: Rp 250.000

Saldo di luar boundary tetap tampil. Sama dengan MCB: yang mati cuma ruangan yang korsleting.

Coba lagi: kembali ke tampilan normal

Fallback biasanya punya tombol "Coba lagi" yang menjalankan this.setState({ hasError: false }), supaya boundary menampilkan anaknya lagi. Perbaiki penyebabnya dulu: kalau user masih null, Profil langsung error lagi dan fallback-nya muncul lagi.

Pola tampilannya sama dengan conditional rendering biasa: satu state boolean memilih satu dari dua tampilan. Di latihan kedua, pola itu ditulis dengan useState:

function App() {
  const [hasError, setHasError] = useState(false)
  return (
    <div>
      {hasError ? (
        <div id="error-ui">Oops! Terjadi kesalahan.</div>
      ) : (
        <div id="normal-ui">Semua berjalan normal</div>
      )}
      <button id="trigger" onClick={() => setHasError(true)}>Trigger Error</button>
      <button id="reset" onClick={() => setHasError(false)}>Reset</button>
    </div>
  )
}

Yang gak ditangkap

Error boundary cuma menangkap error yang terjadi waktu React sedang merender: di dalam function komponen, di constructor, dan di method lifecycle seperti componentDidMount. Yang lolos:

Untuk event handler dan async, tangkap sendiri dengan try/catch, lalu simpan pesannya di state supaya bisa ditampilkan:

function handleSimpan() {
  try {
    simpanData()
  } catch (error) {
    setPesan("Gagal menyimpan: " + error.message)
  }
}

⚠️ Jebakan yang sering ketemu

TL;DR: Error waktu render yang gak tertangkap membuang seluruh tampilan app. Error boundary adalah class component dengan static getDerivedStateFromError (mengubah state jadi { hasError: true }) dan componentDidCatch(error, info) (mencatat error-nya). Selama hasError true, render() menampilkan fallback seperti <div id="fallback">Terjadi error</div>, dan bagian di luar boundary tetap tampil. Reset dengan setState({ hasError: false }) setelah penyebabnya diperbaiki. Boundary gak menangkap error di event handler, kode async, atau dirinya sendiri: tangkap itu dengan try/catch dan simpan pesannya di state.

Yang akan kamu pelajari