<ErrorBoundary> adalah jaring pengaman untuk komponen di dalamnya. Kalau salah satu dari mereka melempar error saat dirender, yang tampil adalah tampilan cadangan (fallback), bukan halaman kosong. Bayangin satu lampu rak di Toko Buku Kak Nadia korslet. Toko yang baik gak mematikan listrik seluruh toko: rak itu saja yang ditutup dengan papan "Rak ini sedang diperbaiki", rak lain tetap buka.
🧪 Tebakan cepat: tombol
Belidi dalamKartuBukumelempar error saat diklik, dan kartunya dibungkus<ErrorBoundary>. Saat tombolnya diklik, fallback-nya muncul atau gak? Jawabannya ada di bagian "Yang gak ditangkap".
Tanpa ErrorBoundary: satu kartu rusak, halaman kosong
Data Bumi Manusia datang tanpa harga:
function KartuBuku(props) {
const harga = "Rp" + props.buku.harga.toLocaleString("id-ID")
return (
<div class="kartu">
<h3>{props.buku.judul}</h3>
<p>{harga}</p>
</div>
)
}
function App() {
const buku = [
{ judul: "Laskar Pelangi", harga: 89000 },
{ judul: "Bumi Manusia" },
]
return (
<div>
<KartuBuku buku={buku[0]} />
<KartuBuku buku={buku[1]} />
</div>
)
}
Diuji di Solid 1.9.17: props.buku.harga bernilai undefined, jadi .toLocaleString berhenti dengan TypeError: Cannot read properties of undefined (reading 'toLocaleString'). Error itu naik sampai render(), dan halamannya kosong, termasuk kartu Laskar Pelangi yang datanya benar.
ErrorBoundary dan fallback(err, reset)
Bentuk dasarnya:
import { ErrorBoundary } from "solid-js"
function App() {
return (
<ErrorBoundary fallback={(err, reset) => (
<div>
<p>Error: {err.message}</p>
<button onClick={reset}>Coba lagi</button>
</div>
)}>
<p>Konten normal</p>
</ErrorBoundary>
)
}
<ErrorBoundary>punya tag pembuka dan tag penutup, karena dia membungkus komponen lain.- Selama isinya gak error, yang tampil isinya:
<p>Konten normal</p>. Fallback-nya gak dibuat sama sekali. fallbackberisi fungsi yang menerima dua hal:err, error yang tertangkap (pesannya dierr.message), danreset, fungsi yang membuat ulang isi boundary-nya.fallbackjuga boleh berisi JSX biasa,fallback={<p>Gagal memuat</p>}, kalau kamu gak butuherrataureset.
Di toko, tiap kartu dibungkus boundary sendiri:
<For each={buku}>
{(b) => (
<ErrorBoundary fallback={(err, reset) => (
<div class="gagal">
<p>Kartu gagal: {err.message}</p>
<button onClick={reset}>Coba lagi</button>
</div>
)}>
<KartuBuku buku={b} />
</ErrorBoundary>
)}
</For>
| Kartu | Yang tampil |
|---|---|
| Laskar Pelangi | kartunya, Rp89.000 |
| Bumi Manusia | Kartu gagal: Cannot read properties of undefined (reading 'toLocaleString') dan tombol Coba lagi |
Satu boundary di luar <For> juga menangkapnya, tapi fallback-nya menggantikan semua kartu sekaligus. Boundary per kartu cuma menutup kartu yang rusak.
reset cuma menggambar ulang. Kalau datanya masih tanpa harga, kartunya gagal lagi dengan pesan yang sama. Perbaiki dulu datanya, misalnya sesudah server mengirim harganya, baru Coba lagi menampilkan Rp120.000.
Yang gak ditangkap
ErrorBoundary menangkap error yang terjadi saat menggambar komponen di dalamnya: di badan komponen, di JSX-nya, dan di createEffect atau createMemo miliknya. Membaca createResource yang gagal di JSX juga melempar errornya di situ, jadi ikut tertangkap.
Yang gak ditangkap:
- Event handler.
onClick={() => { throw new Error("Stok habis") }}jalan jauh sesudah kartunya tampil, waktu tombolnya diklik. Errornya muncul sebagaiUncaught Error: Stok habisdi console, dan kartunya tetap tampil seperti biasa. Itu jawaban tebakannya. - Kode async. Error di dalam
setTimeout, atau sesudahawaitdi handler, terjadi di luar proses menggambar.
Error seperti itu ditangani sendiri dengan try { ... } catch (e) { ... }, lalu pesannya disimpan di signal supaya tampil.
⚠️ Jebakan yang sering ketemu
- Membungkus dengan tag tunggal.
<ErrorBoundary fallback={...} />gak membungkus apa pun. Latihannya memeriksa ada<ErrorBoundarydan</ErrorBoundary>. - Fallback tanpa tombol, atau tombol yang gak memanggil
reset. Latihannya mengklikMuat harga, laluCoba lagi, dan kartunya harus tampil: tombolnya ada di fallback denganonClick={reset}. - Mengira
resetmemperbaiki error. Dia cuma menggambar ulang isinya. Kalau penyebabnya masih ada, fallback-nya muncul lagi. - Mengandalkan boundary untuk klik. Error di
onClicklolos dari boundary. Tangkap dengantry/catchdi handler-nya.
TL;DR: <ErrorBoundary fallback={(err, reset) => ...}>...</ErrorBoundary> membungkus komponen yang bisa gagal. Selama isinya baik, isinya yang tampil (Konten normal). Kalau isinya melempar error saat dirender, tampilan cadangannya yang tampil: err.message berisi pesannya, reset menggambar ulang isinya (yang gagal lagi kalau penyebabnya belum diperbaiki). Tanpa boundary, satu kartu yang rusak mengosongkan seluruh halaman. Boundary menangkap error di badan komponen, JSX, efek, dan resource yang dibaca di JSX, tapi gak menangkap error di event handler atau di kode async.