error.tsx を置いたのに、レイアウトで起きたエラーが拾えませんでした。なぜですか。
error.tsx は同じ階層の layout.tsx の内側に入るからです。layout が外、その中に error、さらに page という順で組み立てられます。境界の外にあるものは受け取れません。
面接官が見ているのは境界の入れ子構造を理解しているか。
これは「あるコンポーネントで例外が出たら、ページ全体が真っ白になりました。どうしますか。」への追撃質問です。
よくある答えと、面談でどう見られるか
- error.tsx は同じ階層の layout の内側に入るため。拾うには親側に置く
ファイル規約の入れ子構造を理解できています。ルートレイアウトのエラーだけはどの error.tsx でも届かず、global-error.js を使います。 - layout はサーバーで実行されるため、エラーバウンダリでは拾えない
サーバーかどうかではなく、境界の内側か外側かの問題です。page で起きたサーバー側のエラーは、同じ階層の error.tsx で拾えます。 - error.tsx が Client Component だから
error.tsx が Client Component である必要があるのは事実ですが、拾えない理由はそこではありません。層の順序の問題です。 - layout にはエラーバウンダリを当てられない仕様のため
当てられないのではなく、当たる位置が1つ上になります。アプリ全体のルートレイアウトについては専用の仕組みがあります。
面接官は何を見ているか
- 同じ階層の layout は境界の外側だと理解している
- 親側に置く必要があると言えた
- 階層構造で考えられている
模範解答
error.tsx は、同じ階層の layout.tsx の内側に入るからです。
ファイル規約は入れ子になっていて、layout が外、その中に error、さらにその中に page、という順で組み立てられます。境界の外にあるものは、その境界では捕まえられません。
公式の言い方では、error.js は loading.js・not-found.js・page.js と配下の layout.js を包みますが、同じ階層の layout.js と template.js は包みません。
なので、ある階層の layout で起きたエラーを拾いたければ、1つ上の階層の error.tsx が必要です。アプリ全体のルートレイアウトで起きたエラーには、どの階層の error.tsx も届きません。これを拾うには global-error.js を使います。
実務的には、レイアウトに重い処理やデータ取得を置かないのが先です。落ちたときの影響範囲が最大になる場所だからです。