Menu

Error Boundary React: Tangkap Error Render dengan Fallback

Error boundary adalah komponen yang menangkap error yang dilempar saat merender komponen di dalamnya dan menampilkan fallback alih-alih layar kosong. Pelajari apa yang ditangkapnya, cara menulisnya sebagai class, cara melakukan reset, dan library react-error-boundary.

Halaman ini dilengkapi editor yang bisa dijalankan. Edit, jalankan, dan lihat output-nya seketika.

Error boundary adalah komponen React yang menangkap error yang dilempar saat merender komponen di dalamnya, lalu menampilkan UI fallback alih-alih membuat seluruh aplikasi crash. Error boundary harus berupa class component yang mendefinisikan static getDerivedStateFromError, karena tidak ada hook untuk ini. Kamu menulisnya sekali lalu membungkuskannya ke bagian mana pun dari tree.

Tekan "Break the profile" agar komponen anak melempar error saat render.

Profil digantikan oleh fallback, dan bagian halaman lainnya tetap berjalan. Konsol menampilkan error-nya dua kali: React mencatat setiap error yang tertangkap dengan console.error, dan componentDidCatch mencatatnya lagi. "Try again" menghapus penyebabnya (broken) dan error milik boundary, jadi profil dirender lagi. Hapus this.props.onReset(); dari reset, dan Try again langsung melempar kembali ke fallback, karena tidak ada yang memperbaiki penyebabnya.

Cara kerja class-nya

Dua method menjadikan sebuah class error boundary:

  • static getDerivedStateFromError(error) berjalan selama render, tepat setelah komponen anak melempar error. Method ini mengembalikan pembaruan state yang mengalihkan boundary ke fallback-nya. Method ini harus murni: tanpa logging, tanpa request.
  • componentDidCatch(error, info) berjalan setelah fallback tampil di layar. Pakai untuk side effect seperti mengirim error ke layanan pelaporan. info.componentStack mendaftar komponen yang melempar error dan komponen-komponen di atasnya.
class ErrorBoundary extends Component {
    state = { error: null };

    static getDerivedStateFromError(error) {
        return { error }; // switch to the fallback
    }

    componentDidCatch(error, info) {
        reportError(error, info.componentStack); // your logging service
    }

    render() {
        if (this.state.error) return this.props.fallback;
        return this.props.children;
    }
}

Tidak ada padanan hook-nya, jadi aplikasi yang seluruhnya ditulis dengan function component pun tetap butuh class yang satu ini. Halaman class component menjelaskan sintaks class jika kamu belum mengenalnya.

Apa yang ditangkap boundary, dan apa yang tidak

Boundary menangkap error yang terjadi saat React mengerjakan komponen di dalamnya:

  • render (isi function component, render milik class),
  • lifecycle method dan constructor dari class component anak,
  • effect (useEffect, useLayoutEffect) dan ref callback,
  • promise yang ditolak dan dibaca dengan use, dan di React 19 juga error yang dilempar oleh form action atau oleh fungsi yang dikirim ke startTransition dari useTransition.

Boundary tidak menangkap:

  • error di event handler,
  • kode async yang kamu mulai sendiri: setTimeout, callback .then(), await di event handler,
  • error di render milik boundary itu sendiri (boundary berikutnya di atas yang menangkapnya),
  • error saat server rendering.

Event handler tidak termasuk karena tidak merusak proses render. Layar masih dalam keadaan valid, jadi try/catch di handler sudah cukup. Jika kamu memang ingin boundary-nya tampil, simpan error itu di state dan lempar di render berikutnya:

Tombol pertama membiarkan tombol-tombolnya tetap di layar dan hanya mencetak error yang tidak tertangkap di konsol. Tombol kedua menangkap penolakannya, menyimpannya, lalu boundary mengambil alih.

Di mana menaruh boundary

Satu boundary yang membungkus seluruh aplikasi mencegah layar putih, tetapi setiap error kecil lalu mengganti semuanya. Taruh boundary di sekitar bagian yang bisa gagal secara terpisah: widget sidebar, grafik, setiap route. Dengan begitu, kegagalan hanya membuat pengguna kehilangan satu panel, bukan satu halaman.

Hanya panel Stocks yang menampilkan fallback-nya. Pindahkan kedua widget ke dalam satu <ErrorBoundary>, dan panel Weather yang berfungsi ikut menghilang.

Tanpa boundary sama sekali, React menghapus seluruh tree dari layar saat error render tidak tertangkap. Halaman kosong lebih aman daripada halaman rusak yang menampilkan data salah, tetapi pengguna menganggapnya crash.

Library react-error-boundary

Package react-error-boundary membungkus class itu untukmu dan menambahkan helper untuk reset. Package ini tidak tersedia di editor ini, jadi berikut contohnya dalam blok statis:

import { ErrorBoundary, useErrorBoundary } from 'react-error-boundary';

function Fallback({ error, resetErrorBoundary }) {
    return (
        <div role="alert">
            <p>Something went wrong: {error.message}</p>
            <button onClick={resetErrorBoundary}>Try again</button>
        </div>
    );
}

<ErrorBoundary FallbackComponent={Fallback} onReset={() => refetch()} resetKeys={[userId]}>
    <Profile userId={userId} />
</ErrorBoundary>;

// Inside a child: hand an async error to the boundary
const { showBoundary } = useErrorBoundary();
fetchData().catch(showBoundary);

resetKeys melakukan reset pada boundary saat salah satu nilai yang didaftarkan berubah, dan showBoundary melakukan trik "simpan lalu lempar" dari contoh sebelumnya.

Melaporkan error di React 19

React 19 melaporkan error dengan cara baru. Error yang ditangkap boundary dicatat sekali dengan console.error, dan error yang tidak tertangkap dikirim ke window.reportError. Untuk mengirimnya ke layananmu sendiri, kirim opsi ke createRoot. Setiap opsi menggantikan logging default yang sesuai:

import { createRoot } from 'react-dom/client';

const root = createRoot(document.getElementById('root'), {
    onCaughtError(error, errorInfo) {
        // an error boundary caught it
        logToService('caught', error, errorInfo.componentStack);
    },
    onUncaughtError(error, errorInfo) {
        // no boundary caught it, and React removed the tree
        logToService('uncaught', error, errorInfo.componentStack);
    },
    onRecoverableError(error, errorInfo) {
        // React recovered by itself, for example after a hydration mismatch
        logToService('recovered', error, errorInfo.componentStack);
    },
});
root.render(<App />);

onRecoverableError untuk error yang diperbaiki React tanpa bantuanmu, seperti hydration mismatch atau error render yang hilang saat React mencoba lagi. hydrateRoot menerima tiga opsi yang sama.

Kesalahan umum

Menaruh boundary di dalam komponen yang melempar error. Boundary hanya menangkap error dari komponen anaknya. Jika Profile merender <ErrorBoundary> di sekitar JSX miliknya sendiri lalu melempar error di isi fungsinya sendiri, error itu melewatinya ke boundary berikutnya di atas. Bungkus komponen itu dari induknya.

Side effect di getDerivedStateFromError. Method ini berjalan selama render dan bisa berjalan lebih dari sekali, jadi batasi isinya hanya untuk mengembalikan state. Logging tempatnya di componentDidCatch atau di onCaughtError milik root.

Reset yang tidak memperbaiki apa pun. Menghapus error milik boundary merender anak yang sama dengan props yang sama. Jika anak itu melempar error lagi, pengguna kembali ke fallback. Ubah dulu penyebab error-nya (ambil ulang data, bersihkan input yang salah, ubah key), baru hapus error-nya, seperti yang dilakukan contoh pertama dengan onReset.

Satu boundary untuk seluruh aplikasi, dan tidak ada yang lain. Cara ini mencegah halaman kosong, tetapi mengubah setiap kegagalan kecil menjadi error satu halaman penuh. Tambahkan boundary di sekitar fitur, dan pertahankan boundary teratas sebagai pertahanan terakhir.

Fallback yang menyembunyikan error darimu. Pesan yang ramah memang tepat untuk pengguna, tetapi pastikan error-nya tetap sampai ke log-mu. React 19 secara default mencatat error yang tertangkap ke konsol; di production, konsol itu milik penggunamu, jadi kirim error ke sebuah layanan dari componentDidCatch atau onCaughtError.

Error boundary cocok dipasangkan dengan <Suspense>: Suspense menangani "belum siap", boundary menangani "gagal". Taruh boundary di luar Suspense, seperti pada contoh use, agar satu komponen mencakup loading, berhasil, dan gagal.

Pertanyaan yang sering diajukan

Apa itu error boundary di React?

Error boundary adalah komponen yang menangkap error JavaScript yang dilempar saat merender komponen apa pun di dalamnya, lalu merender UI fallback sebagai gantinya. Tanpa error boundary, error saat render menghapus seluruh aplikasi dari layar.

Apakah ada hook untuk error boundary?

Tidak. Error boundary harus berupa class component dengan static getDerivedStateFromError (dan opsional componentDidCatch). Kamu menulisnya sekali lalu memakainya dari function component seperti komponen lain, atau pasang react-error-boundary, yang membungkus class itu untukmu.

Apakah error boundary menangkap error di event handler?

Tidak. Event handler berjalan di luar proses render, jadi React tidak butuh boundary untuk pulih. Pakai try/catch di handler, dan jika kamu ingin boundary-nya tampil, simpan error itu di state lalu lempar saat render.

Apakah error boundary menangkap error async?

Tidak untuk setTimeout, callback promise, atau fetch().then() yang kamu mulai sendiri. Error boundary menangkap promise yang ditolak dan dibaca dengan use, dan di React 19 juga error yang dilempar di dalam form action atau fungsi yang dikirim ke startTransition dari useTransition.

Bagaimana cara melakukan reset pada error boundary?

Hapus state error-nya, biasanya dari tombol Try again di fallback, setelah memperbaiki penyebab error-nya. Mengubah key milik boundary juga melakukan reset, karena React membuat instance baru saat mount.

Ilustrasi bahasa pemrograman di Coddy

Belajar coding dengan Coddy

Mulai