- Published on
App Routerを本番投入した感想
- Authors
- Name
- nu0ma
- @nu0ma
前書き
最近本業で App Router をプロダクション環境にリリースしたので感想や設計について書いていく。 App Router がそもそもどのようなものかはこちら。
感想
感想としては、コロケーションすることでページ単位のコンポーネントをまとめて置くことができるのでシンプルに作ることができる。 Moving Client Components to the Leaves にもあるが、CC をできるだけツリーの端に置くことは重要だった。 あとは App Router に対応していないライブラリを使用する場合は自分で export し直す必要があるが、これもドキュメントに書かれていた ⇨ Third-party packages。
設計
App Router でのフォルダ分割をどうするかについては、コロケーションを重視してフォルダを切った。わかりやすくて良い。 具体的には下記のようにした。
.
└── app/
├── great_page/
│ ├── _components/
│ │ ├── Form.tsx
│ │ ├── Form.test.tsx
│ │ ├── Form.stories.tsx
│ │ └── ...
│ ├── _api/
│ │ ├── getUser.ts
│ │ └── ....
│ ├── __types/
│ │ ├── user.ts
│ │ └── ...
│ ├── page.tsx
│ ├── error.tsx
│ └── layout.tex
└── _components/
├── Button.tsx
└── ....
_をフォルダ名の先頭に付けると、ルートとして認識されないのを利用して、ページで使うコンポーネントはページ名のフォルダ内部に集約した。 一方で全体のページで使用されるコンポーネントは app 直下に_components
というフォルダを作りそこに置いた。
後から知ったが Next.js の中の人もおすすめしていた設計だった。
Great feedback, thank you! It is indeed up to you, the pattern we found useful so far is a _components directory collocated with the route if there are specific components. Otherwise use app/_components. https://twitter.com/timneutkens/status/1659313703374712833
それぞれのルート直下のpage.tsx
でコンポーネントを呼び出して、非同期コンポーネントはSuspence
でラップして fallback を表示させるという風にした。
データフェッチに関しては、Hooks などは経由せずにコンポーネント内部でそのままコンポーネントが必要なデータを取得するようにし、コロケーションをここでも実行した。 と言っても公式ドキュメントにもある通り。
import Albums from './albums'
async function getArtist(username: string) {
const res = await fetch(`https://api.example.com/artist/${username}`)
return res.json()
}
async function getArtistAlbums(username: string) {
const res = await fetch(`https://api.example.com/artist/${username}/albums`)
return res.json()
}
export default async function Page({ params: { username } }: { params: { username: string } }) {
// Initiate both requests in parallel
const artistData = getArtist(username)
const albumsData = getArtistAlbums(username)
// Wait for the promises to resolve
const [artist, albums] = await Promise.all([artistData, albumsData])
return (
<>
<h1>{artist.name}</h1>
<Albums list={albums}></Albums>
</>
)
}
// https://nextjs.org/docs/app/building-your-application/data-fetching/fetching#parallel-data-fetching
余談
初めて Next.js を触る人とペアプロした際に、わかりやすいですねと言っていて、自分からすると Page Routes からだいぶ複雑になったと思っていたが メンタルモデルは意外と単純になったのかもしれないと思った。