Closed9

Next.js App Router Parallel Routes の default.js & 404 メモ

nbstshnbstsh

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 になる。

nbstshnbstsh

例) /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 になる。

nbstshnbstsh

対策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.

https://nextjs.org/docs/app/building-your-application/routing/parallel-routes#defaultjs

@b slot に default.tsx を用意する。

app/@b/default.tsx
const SlotBDefault = () => {
  return <div>@b root default</div>;
};

export default SlotBDefault;

/sub にアクセスすると、@b slot は default.tsx が表示される↓

nbstshnbstsh

対策2: Catch-all route を利用する

slot 内に catch-all routeを用意することで、404 を回避することも可能。

https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes#catch-all-segments

@b slot 内に [...catchAll] の形で catch-all route を用意。

app/@b/[...catchAll]/page.tsx
const SlotBCatchAllPage = () => {
  return <div>@b catch-all page</div>;
};

export default SlotBCatchAllPage;

/sub にアクセスすると、@b slot の catch-all route page が表示される。

nbstshnbstsh

default.js と catch-all route の違い

default.js

Hard Navigation 時に明示的に match する route が存在しない場合に表示される。

catch-all route

明示的に match する route が存在しない場合に常に表示される。

nbstshnbstsh

例) /sub を default.js と catch-all route でそれぞれ表示

  • @a slot は /sub の route が存在する
  • @b slot は /sub の route は存在せず、 catch-all route で対応
  • @c slot は /sub の route は存在せず、default.js で対応

app/@b/[...catchAll]/page.tsx
const SlotBCatchAllPage = () => {
  return <div>@b catch-all page</div>;
};

export default SlotBCatchAllPage;
app/@c/default.tsx
const SlotCDefault = () => {
  return <div>@c root default</div>;
};

export default SlotCDefault;

1. /sub を表示する (Hard Navigation)

catch-all route も default.js もどちらも表示されている↓

この状態で /sub => / と Soft Navigation すると、どちらも slot の root の page.tsx が表示される。(= 明示的に match する route が存在する場合は、どちらもその page.tsx を表示)

2. / から遷移して /sub を表示する (Soft Navigation)

まず / を表示する。

この状態で "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 がそのまま表示される ことがわかる。

nbstshnbstsh

ポイントまとめ

  • 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.

https://nextjs.org/docs/app/api-reference/file-conventions/default

nbstshnbstsh

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 になってしまう↓

https://nextjs.org/docs/app/api-reference/file-conventions/default

このスクラップは2024/02/25にクローズされました