Next.jsのAppルーターでルーティングする際のファイル名規則について。
以下の記事の続き。基本的なことは以下で。
Next.jsのAppルーターではルーティング対象になるファイル名があらかじめ予約されていて、それらには意味がある。
各名称ごとに役割があり、かつ、特定の順番で階層化される。
各ファイル名の意味
- page ⇒ フォルダの中に作ることでルーティングされてページが表示される。基本の基本の基本。
- layout ⇒ childrenの中にpageの内容が入る。同じルート配下の子は全て親のレイアウトにネストされる。
- template ⇒ 同一ルート内で遷移した時に再レンダリングするレイアウト。layoutは再レンダリングされない。
- error ⇒ エラー処理。React Error Boundaryで自動でラップされる
- global-error ⇒ errorのグローバル版。
- loading ⇒ ReactのSuspenseを使う機能
- not-found ⇒ 存在しないURLにアクセスがあった時の処理
- route ⇒ APIエンドポイント
- default ⇒ 何に使うか不明
page
基本の基本になるのがpage。
フォルダの中にpageファイルを作ることで、ページが表示される。
pageが無いとルーティングされない。
app直下に作ったpageがトップページになる。
pageは基本的に「サーバーコンポーネント」になる。
pageではfetchを使ってデータ取得できる。
同一階層と先祖階層のlayout、template、error、loadingにネストされる。
layout
複数ページで共有されるUIを設定するところ。
children
が必要。children
の中に、pageの内容が入る。
layoutはネストされるので、ルートの下全てに反映されるので、app直下に作ったlayout(ルートレイアウト)は全ページに反映される。
ルートレイアウトは必須。ルートレイアウトにhtml
とbody
が必要。
ルートグループを使うことで、ルートレイアウトを複数作ったり、ネストしない形にすることもできる。
レイアウトは基本はサーバーコンポーネントになる。
pageと同様に、fetchでデータ取得できる。
レイアウト間ではデータのやり取りができないので、各レイアウトで個別にfetchする必要がある。
templates
この機能はまだ実際に試していないのでわからないが、テキストを読む限りでは同一ルート内で遷移した時に再レンダリングするレイアウト、らしい。レイアウトは再レンダリングされないらしい。
基本的にはレイアウトと同じで、再レンダリングの有無が大きな違いっぽい。
next/linkとの関係性とか良くわからない。
next/linkを使うとuseEffectが起動しなくて再レンダリングできないのだけど、以下の例のようにすると動く。
templates内に書けば、これが無くてもnext/linkで再レンダリングされるのかどうかは知らない。
templatesの機能はテキストを読むだけだと、細かい挙動が想像できない。今後の課題。
errorとglobal-error
errorは、React Error Boundaryで自動的にラップしてくれるファイル。
階層ごとに作れるので、エラーを切り分けて、エラー用の表示と解決策を設定することができる。
ルートコンポーネントに対してエラー処理する場合はglobal-errorを作る必要がある。
errorはクライアントコンポーネントになるので、'use client'
表記する。
クライアント側への機密情報漏洩を避けるために、サーバーコンポーネントでエラーがあった場合、特定のエラーの詳細が削除される。
同一階層だとレイアウト内にネストされるので、レイアウトに対してのエラー処理をしたい場合は、対象のレイアウトの親階層に入れる必要がある。
loading
ReactのSuspenseを差し込んでくれるのがloading。
Suspenseはロード中のアニメーションなどで使われるあれ。
コンポーネントのロードに時間がかかる場合に、「コンポーネントがローディング中なので今はレンダリングできないよ」という状態にしておけて、ロードするまでの間に別のURを表示しておける、というもの。
<Suspense fallback={<div>ロード中はここが表示される</div>}> {/* 通常はここが表示される */} <MyComponent /> </Suspense>
Next.jsでloadingを作ると、Suspenseのfallbackにloadingが設定される。
not-found
存在しないURLにアクセスした時に表示されるページを作ることができる。要は404ページみたいなもの。
v13.3以降はapp直下に置けばサイト全体の404ページとして機能する。v14では一応想定通りに動いている。
ただし、generateStaticParamsのdynamicParamsの設定や、error.tsの設定と競合する。各種設定や、not-foundがどの階層に置いてあるかで挙動が変わるので注意か必要。
route
APIが作れる。
具体的な例は以下。
default
Next.js公式には、ドキュメントページはあるけど中身はまだないため、何のためにあるのかよくわからない。
階層の順番
各ページは基本的にコンポーネントととして階層化されてレンダリングされる。
以下の順番。
<Layout> <Template> <ErrprBoundry fallback={<Error />}> <Suspense fallback={<Loading />}> <Page /> </Suspense> </ErrprBoundry> </Template> </Layout>
各種コンポーネントはネストされる。
以下のようなフォルダ構成の場合。
└─ test1 ├─ layout.tsx ├─ error.tsx ├─ loading.tsx └─ test2 ├─ layout.tsx ├─ error.tsx ├─ error.tsx ├─ loading.tsx └─ page.tsx
以下のようにネストされる。
<Layout> <ErrprBoundry fallback={<Error />}> <Suspense fallback={<Loading />}> <Layout> <ErrprBoundry fallback={<Error />}> <Suspense fallback={<Loading />}> <Page /> </Suspense> </ErrprBoundry> </Layout> </Suspense> </ErrprBoundry> </Layout>
まとめ
pagesルーターでは好きに名前が使えてルーティングされるときのURLになったのだけど、Appルーターではpageが入っているフォルダ名がURLになった。
Next.jsで予約されている名前もあるため、ルーティングされない部分はプライベートフォルダを使うのがわかりやすそう。
layoutは便利だけど、他のフレームワークにあるslot的な機能はないため、ちょっと使いにくい。共通のコンポーネントを配置する場所、という位置づけのほうが良さそうな気がする。日本語の意味でのレイアウトとして使おうとすると、slotが欲しくなる。
v14時点では、not-foundとerrorは同一階層に置いておくと、errorのほうが優先されるみたいで、他の機能とどう競合するのかいまいちよくわからない部分がある。
loadingはReactのSuspenseを手軽に使えそうで便利。
templatesをまだ試せてないのが、今後の課題。