白猫のメモ帳

C#とかJavaとかJavaScriptとかHTMLとか機械学習とか。

Next.js(App Router)を試してみる2(ルーティング)

こんにちは。
お盆ですね。Googleで「お盆」でサジェストすると「お盆 2023」とか出てきてスポーツの祭典みを感じます。

前回はとりあえずNext.jsのアプリを作ったので、今回はルーティング周りを見ていきます。

ルートのルーティング

Next.jsのURLルーティングはファイルシステムをそのまま反映します。
アプリケーションのデフォルトのURLの「http://localhost:3000」を例にすると、

http://localhost:3000

は「src/app/page.tsx」にルーティングされます。その際に同じ階層にある「src/app/layout.tsx」をレイアウトファイルとして読み込みます。

つまりpage.tsxを以下のように編集して、

export default function Home() {
  return (<p>Hello</p>)
}

layout.tsxは以下のようにすると(特に編集なし)、

import './globals.css'
import type { Metadata } from 'next'
import { Inter } from 'next/font/google'

const inter = Inter({ subsets: ['latin'] })

export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body className={inter.className}>{children}</body>
    </html>
  )
}

出力されるHTMLはこんな感じになります。
(実際には<!DOCTYPE html>だったり<head<タグが勝手に差し込まれたりします)

<html lang="en">
  <body className="__className_20951f"><p>Hello</p></body>
</html>

tsxはTypeScript のファイルの中でHTML のような記述ができる構文拡張です。
同様にjsxはJavaScriptの構文拡張で、どちらもNext.jsの機能ではなく、Reactの機能です。

任意のURLにルーティング

http://localhost:3000/hoge

にルーティングしたい場合には「src/app/hoge/page.tsx」を作ります。

export default function Hoge() {
  return (<p>hoge</p>)
}

ちなみにlayout.tsxは「同じ階層のレイアウトファイル」ではなく「同じ階層とその子のレイアウトファイル」なので、「src/app/layout.tsx」も読み込まれます。なので「src/app/hoge/layout.tsx」を以下のように作ると

export default function HogeLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <div className="outer">{children}</div>
  )
}

両方読み込まれてこうなります。

<html lang="en">
  <body className="__className_20951f"><div className="outer"><p>Hello</p></div></body>
</html>

page.tsxとlayout.tsxの他にもerror.tsxなども置けるみたいですね。
Building Your Application: Routing | Next.js

動的ルーティング

URLが静的な場合にはそのままディレクトリ名にすれば問題ないですが、URLが動的な場合にはそうもいきません。
例えばブログの記事URLを「~/entry/【記事ID】」とかにしたい場合にはカッコを使って、「src/app/entry/[postId]/page.tsx」を作ります。
(パスにカッコ入ってるのちょっと違和感ありますがそういうものらしい)

そしてパスの情報はパラメタとして渡すことができるので、これを受け取れば動的URLをルーティングできます。

http://localhost:3000/entry/aaa

export default function Blog({ params }: { params: { postId: string } }) {
  return (<p>{params.postId}</p>)
}

ちなみにこの定義だと以下のようなURLはルーティングできません。

http://localhost:3000/entry/aaa/bbb/ccc

この場合には「src/app/entry/[...postId]/page.tsx」を作ります。「...」を前につけるとその後ろを全部ルーティングして、配列としてパラメタに渡してくれます。

export default function Blog({ params }: { params: { postIds: string[] } }) {
  return (
    <>
      {params.postIds.map((postId) => (<p key={postId}>{postId}</p>))}
    </>
  )
}

URLの書き換え

ファイルシステムベースでURLが自動で割り当てられるのはうれしいですが、URLを書き換えたいときもあります。mod_rewriteみたいに。そんな場合にはnext.config.jsにrewritesの定義を足すとできます。

module.exports = {
  async rewrites() {
    return [
      {
        source: '/blog/:path*',
        destination: '/entry/:path*',
      },
    ]
  },
}

予想はつくかと思いますが、リダイレクトもできます。

module.exports = {
  async redirects() {
    return [
      {
        source: '/blog/:path*',
        destination: '/entry/:path*',
        permanent: false
      },
    ]
  },
}

ちょっとした設定

リバプロの後ろに置いたりする場合にはルートのURLを変更したくなります。ASP.NETの時のUsePathBaseみたいなやつです。そんな時にはnext.config.jsに「basePath」を設定します。

URLのトレイリングスラッシュを強制したい気もします。そんな時にもnext.config.jsに「trailingSlash」を設定します。

module.exports = {
    basePath: '/sample',
    trailingSlash: true,
}

一般的なWebアプリケーションに必要な設定はnext.config.jsで何とかできそうな感じがしますね。

ルーティング周りの基本的な機能はわかったかも

触りながら覚えるのもいいけど、先にドキュメントに目を通しておくと理解しやすくて良き。