Error Boundary'yi Layout'a Koymak
error.tsx aynı segmentteki layout'u yakalamaz

Nadir bir veritabanı hatasında tüm pazarlama sitesi beyazladı. error.tsx layout'un yanındaydı, içinde 'bir şey bozuldu' yazıyordu. Layout, nav için kategori çekiyordu. error.tsx o layout'u sarmıyor. Aynı segmentte layout dışarıda, page içeride. Layout patlayınca sınır devreye girmiyor, yukarı çıkıyor. Yukarıda sınır yoksa beyaz sayfa.
Kimin içinde, kimin dışında
Belge açık: error.js, children'ı yani page ve alt segmentleri yakalar. Layout ve template, o error dosyasının dışında kalır. global-error root layout'u yakalar; o da html ve body'yi senin yazmanı ister. Nav'da fetch varsa hata ya global'e gider ya da nav'ı page'den ayırmazsın.
"use client";
export default function ShopError({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
Vitrin şu an açılamıyor.
{error.digest ? `Kod: ${error.digest}` : "Yenilemeyi dene."}
);
}
// app/shop/layout.tsx — yalnızca kabuk, fetch yok
export default function ShopLayout({ children }: { children: React.ReactNode }) {
return (
Mağaza
{children}
);
}
// app/shop/page.tsx — kırılgan sorgu burada
import { listProducts } from "@/lib/catalog";
export default async function ShopPage() {
const products = await listProducts();
return (
{products.map((p) => (
- {p.name}
))}
);
}
Kategorileri layout'tan alıp page'e indirdim. Nav statik linklerle kaldı. listProducts patlayınca shop/error.tsx vitrini sarar, site başlığı yerinde durur. Root layout'taki font ve çerez penceresi de yerinde kalır. Beyaz sayfa, 'error dosyam var' diye kapanmaz; dosyanın hangi ağacı sardığıyla kapanır.
reset(), o segmenti yeniden render eder. Layout'taki bozuk fetch'i reset ile iyileştiremem; çünkü layout sınırın dışında. Fetch'i sınıra sokmak, dosyayı aşağı taşımaktır. global-error'u son çare bırakıyorum: root layout gerçekten kırıldığında, marka rengi ve bir yenile düğmesi. Her 500'ü global'e yıkmak, nav'sız bir hata tiyatrosu.
error.tsx client olmak zorunda
reset bir event. Dosya 'use client' ister. Bunu unutup sunucu error yazmak derlemede kırılır. digest'i kullanıcıya olduğu gibi dökmek yerine kısa bir kod olarak gösteriyorum; stack production'da zaten yok. Log tarafında digest ile iz sürmek ayrı iş. Sınır UI'si özür diler, debug etmez.
Aynı klasöre loading.tsx koymak error'u değiştirmez. Örtü, beklerken durur; sınır, patlayınca durur. İkisini yan yana görmek, dördüncü yazıyla bu yazıyı bağlar. Layout fetch'i ikisini de bozar: örtü layout'u beklemez, sınır layout'u yakalamaz. Veriyi page'e indirmek iki dosyayı birden işe yarar.
Nested route
shop/error.tsx, shop/orders/page patlayınca da devreye girebilir; daha yakın bir orders/error.tsx yoksa. Yakın olan kazanır. Sipariş listesinin hatasını vitrin iskeletiyle göstermek kaba. orders klasörüne kendi sınırını koyuyorum. Kökte tek error.tsx, her şeyi aynı özürle boyar. Özür aynı olabilir, bağlam aynı değildir. 'Vitrin açılamıyor' siparişte yalan.
notFound ile error
Kayıt yoksa throw değil, notFound(). notFound, error.tsx'e değil, not-found.tsx'e düşer. İkisini karıştırmak, 404'ü 500 gibi özürletir. Layout hâlâ yerinde kalır; bu, not-found'un da segmentte durduğu anlamına gelir. Root not-found ayrı. 'Bulunamadı'yı error sınırına yıkmak, reset düğmeli bir 404 üretir. Reset, kaydı geri getirmez.
Beklenen hata ile beklenmeyen hata. Stok bitmesi beklenen bir durum olabilir, UI'da mesaj. Bağlantı kopması beklenmeyen, sınır. Her throw bir sınır değildir. Action içindeki doğrulama hatasını throw edip error.tsx'e düşürmek, dokuzuncu yazıda konuştuğum beyaz yorum kutusu. error.tsx, programın şaşırdığı yer. Kullanıcının yanlış doldurduğu yer değil.
template.tsx
template, layout gibi sarar ama navigasyonda remount olur. error sınırını template'e bağlamak nadiren gerekir. Asıl karışıklık, fetch'i template'e koymak: her geçişte tekrar patlar, sınır her geçişte yakalar, kullanıcı reset döngüsünde kalır. Fetch page'de, sınır page'in yanında, layout sakin. Bu üçlü durunca beyaz sayfa, nadir root hatasına iner.
On birinci yazının cümlesi: error dosyasının yeri, patlayan await'in yeridir. Layout'ta await varsa sınır orada işe yaramaz. Await'i indir, sınır işe yarar. Dosyayı layout'un yanına koyup 'ben hata yönetiyorum' demek, yönetmediğin bir ağacı işaretlemek. İşaret, beyaz sayfayı gizlemez.
digest ve log
Production'da mesaj gizlenir, digest kalır. Kullanıcıya digest göstermek, destek ile log'u birleştirir. Stack göstermemek. error.tsx içinde console.error, geliştirmede yeter; production'da bir raporlama çağrısı. Çağrıyı layout'ta yapmak, layout patlayınca çağrı da ölür. Sınırın içinde raporla. Layout sakin kalsın ki rapor gidebilsin.
Aynı hata üç segmentte birden yakalanmasın diye sınırları iç içe boğmuyorum. Yakın olan kazansın. Uzak olan genel özür. İkisinin metni farklı. Bu, on birinci yazının son tekrarı: yer, metin, await. Üçü hizalanınca beyaz sayfa kaybolur. Hizalanmayınca error.tsx bir süs dosyasıdır.
Client throw
Yaprak throw ederse de aynı error.tsx yakalayabilir; dosya client olduğu için. Sunucu await'i page'de, client throw'u yaprakta. İkisini layout'a yığmak yine dışarıda kalır. Layout'ta client bir menü patlarsa ve menü layout'un içindeyse sınır yine dışarıda. Menüyü children'a veya kendi segmentine al. Patlama, sınırın içinde doğmalı. Doğmazsa beyaz sayfa geri gelir.
Bu yüzden kırılgan işi layout'tan süpürüyorum: fetch, rastgele tarih, üçüncü parti widget. Widget bir yaprak, fetch bir page, layout bir çerçeve. Çerçeve patlamasın. Patlarsa global-error, o da nadir. Nadir olanı sık görüyorsam sınır yanlış yerdedir, widget değil.
Yorumlar
Yorumlar (0)
Yorumlar üyelere açık. Üye ol · Giriş yap