Next.js App Router Parallel Routes の default.js & 404 メモ
App Router の Parallel Routes で遊んでいた際に、思ったように動かなかった点をメモしていく
404 になるケース
Hard Navigation: After a full-page load (browser refresh), Next.js cannot determine the active state for the slots that don't match the current URL. Instead, it will render a default.js file for the unmatched slots, or 404 if default.js doesn't exist.
Parallel Routes の slot の内 match する route が 存在しない slot が一つでもあった場合、404 になる。
/sub
page を表示したいケース
例) - src/app/@a/sub/page.tsx
- src/app/@b/page.tsx
- src/app/sub/page.tsx
=> @b slot には /sub/page.tsx
がない
この状態で /sub
にアクセスすると 404 になる。
対策1. default.js を用意する
You can define a default.js file to render as a fallback for unmatched slots during the initial load or full-page reload.
@b slot に default.tsx
を用意する。
const SlotBDefault = () => {
return <div>@b root default</div>;
};
export default SlotBDefault;
/sub
にアクセスすると、@b slot は default.tsx が表示される↓
対策2: Catch-all route を利用する
slot 内に catch-all routeを用意することで、404 を回避することも可能。
@b slot 内に [...catchAll]
の形で catch-all route を用意。
const SlotBCatchAllPage = () => {
return <div>@b catch-all page</div>;
};
export default SlotBCatchAllPage;
/sub
にアクセスすると、@b slot の catch-all route page が表示される。
default.js と catch-all route の違い
default.js
Hard Navigation 時に明示的に match する route が存在しない場合に表示される。
catch-all route
明示的に match する route が存在しない場合に常に表示される。
/sub
を default.js と catch-all route でそれぞれ表示
例) - @a slot は
/sub
の route が存在する - @b slot は
/sub
の route は存在せず、 catch-all route で対応 - @c slot は
/sub
の route は存在せず、default.js で対応
const SlotBCatchAllPage = () => {
return <div>@b catch-all page</div>;
};
export default SlotBCatchAllPage;
const SlotCDefault = () => {
return <div>@c root default</div>;
};
export default SlotCDefault;
/sub
を表示する (Hard Navigation)
1. catch-all route も default.js もどちらも表示されている↓
この状態で /sub
=> /
と Soft Navigation すると、どちらも slot の root の page.tsx が表示される。(= 明示的に match する route が存在する場合は、どちらもその page.tsx を表示)
/
から遷移して /sub
を表示する (Soft Navigation)
2. まず /
を表示する。
この状態で "Sub Page" の Link から /
=> /sub
と Soft Navigation する。
すると、以下の挙動になる。
- @b: catch-all route が表示
- @c: slot root の page.tsx が表示
一度 slot 内で明示的に match した page が表示された後に Soft Navigation で画面遷移する際、 slot 内のどの route にも match しなかった場合、default.js ではなく、すでに表示されている page がそのまま表示される ことがわかる。
ポイントまとめ
- default.js は Url に対応する route が存在しない場合に常に表示されるわけではない
- default.js は Hard Navigation (full-page load)時に Url に対応する route が存在しない場合に表示される。
The default.js file is used to render a fallback within Parallel Routes when Next.js cannot recover a slot's active state after a full-page load.
During soft navigation, Next.js keeps track of the active state (subpage) for each slot. However, for hard navigations (full-page load), Next.js cannot recover the active state. In this case, a default.js file can be rendered for subpages that don't match the current URL.
app/default.js について
Parallel Routes のどれか一つでも match する route が 存在しない slot があった場合、404 になる。
これは、app/*
の一般的な route も例外ではない。
というのも、
The children prop is an implicit slot that does not need to be mapped to a folder. This means app/page.js is equivalent to app/@children/page.js.
Layout component で利用する children
も Parallel Route の slot で、app/page.js
は暗黙的に app/@children/page.js
と解釈される。
すなわち、上述した、default.js や catch-all route の話は app/*
にも当てはまる。
公式 Doc の下記画像の例では、app/default.js
が存在しないと、/settings
を表示する際に @children slot 内で対応する route が存在しないため 404 になってしまう↓