Tips

最新版!Next.js14をインストールからルーティング(画面遷移)まで解説【[id],[[…slug]],not-found.tsx,layout.tsx, Link, error.tsx, loading.tsx】

  • このエントリーをはてなブックマークに追加

「Reactは習得できたからNext.jsを触ってみたい」
「Next.jsを勉強しているけど古い記事だとコマンドやコードが違うため扱えない」
「Next.jsを使いたいけどインストールの時点でよくわからないエラーに当たる」

本日はそんな方に向けてNext.jsの最新バージョン14のインストール方法を解説していきます。

最新のWeb開発のフレームワークであるNext.jsはその柔軟性と効率性において、ますます注目を集めています。

特にバージョン14では多くの新機能や改善点が導入され、開発者にとってより魅力的な選択肢となっています。

この記事ではNext.jsの最新バージョンである14をインストールから解説し、その新機能や変更点を詳しく掘り下げていきます。

次世代のWebアプリケーション開発における最先端のツールとテクノロジーを取り入れるために、本記事を通じてNext.jsの最新版を理解し活用する手助けを行います。

最新のNext.js14のインストール手順

Next.js14についてはまだ使用していない会社が多くあるかもしれませんが、新しい機能が搭載されているので順次アップデートされていく見込みです。

本記事の執筆日時点で公式サイトではNode.jsのバージョンを18.17以上にすることを求めています。

https://nextjs.org/docs/getting-started/installation

試しに18.00と少し下げたバージョンのNode.jsがインストールされた状態でNext.jsのインストールコマンドを実行してもインストールはできてもローカルサーバーが立ち上がりませんでした。

ご自身のNode.jsのバージョンを確認の方法はターミナルで以下のコマンドを打って返ってくる数字を確認します。

また「Not Found」などが表示された場合はそもそもNode.jsがパソコン上にインストールされていないことになります。

node -v

初めてインストールする、アップグレードされる方は以下のサイトより手順を確認しましょう。

https://nodejs.org/en

Node.jsが新しいバージョンでインストールされている状態になれば、Next.jsのインストールコマンドを任意のディレクトリで実行します。

npx create-next-app@latest

こちらのコマンドで初期設定のための質問が何点かターミナル上で表示されるので「yes」「no」をスペースキーで選択してエンターキーを押していきます。

今回はTypeScript込みでNext.jsを使用しますので以下の回答にしました。

What is your project named?  
→next-demoと入力してEnter

Would you like to use TypeScript? No / Yes
→Yesを選択してEnter

Would you like to use ESLint? No / Yes
→Yesを選択してEnter

Would you like to use Tailwind CSS? No / Yes
→Yesを選択してEnter

Would you like to use `src/` directory? No / Yes
→Yesを選択してEnter

Would you like to use App Router? (recommended) No / Yes
→Yesを選択してEnter

Would you like to customize the default import alias (@/*)? No / Yes
→Noを選択してEnter

全ての回答が終わるとインストールが開始されますので3分程度待ちます。

インストールが完了すると上記の一番最初の質問で入力したキーワード名でフォルダが作成されます。

作成されたフォルダまでcdコマンドで移動しましょう。

本記事では「next-demo」というフォルダが作成されましたので以下のように実行します。

cd next-demo

Reactと同じくNext.jsではローカルサーバーでブラウザ表示ができますので以下のコマンドを実行します。

npm run dev

そうすると以下のようなターミナルになるので「http://localhost」から始まるURLをブラウザで立ち上げます。

上図の場合だと「http://localhost:3000」をブラウザで立ち上げると画面が表示されます。

画面にも表示されていますがNext.jsは/src/app/page.tsxがトップページとして使用されます。

そのためpage.tsxの中身を以下のように変えてみます。

import React from 'react';

const page = () => {
  return <div>page</div>;import React from 'react';

const page = () => {
  return <div>page</div>;
};

export default page;
};

export default page;

そうすると画面の状態は以下のように切り替わることが確認できます。

Next.js14におけるルーティングのやり方

Next.jsのルーティングの特徴としては、ブラウザでアクセスできるURLはファイルとフォルダの階層によって決定される点です。

すべてのルートは「/src/app」フォルダ内に配置するのが大前提のルールとしてあります。

またファイル名はTypeScriptなら「page.tsx」、JavaScriptのみであれば「page.jsx」とすることになっています。

下層ページについては「/src/app」以下の各フォルダ名がURLのクエリに対応しています。

以下のようなディレクトリ構成を作ってみます。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-page.tsx
    |-layout.tsx 

「/src/app/page.tsx」「/src/app/layouy.tsx」はすでにあるので、「/src/app/about/page.tsx」「/src/app/contact/page.tsx」を新しく追加します。

import React from 'react';

const page = () => {
  return <div>About</div>;
};

export default page;
import React from 'react';

const page = () => {
  return <div>contact</div>;
};

export default page;

ここまでの状態でブラウザの状態を確認してみると「http://localhost:3000」は以下のトップページです。

つづいて「http://localhost/about」にアクセスするとページが変わります。

さらに「http://localhost/contact」にアクセスするとさらにページが切り替わります。

ちなみに存在しないディレクトリ名をURLのクエリにすると自動的に404ページのような扱いになります。

例えば「http://localhost:3000/xxxxx」としてみると以下のようになるはずです。

本来であれば404ページになるページを「NotFound.tsx」のようにファイルを作成してコーディングしておく必要があるはずですが、Next.jsでは自動的にファイルが生成される仕組みになっています。

先ほど紹介したディレクトリ構成でルーティングが動作する仕組みと併せてルール化された仕様になっているのです。

ちなみにオリジナルの404ページを作成したいときは「/src/app/not-found.tsx」というファイルを作成すると自動的にnot-found.tsxで作成された内容が404ページに差し替えられます。

ファイル名は固定ですので注意してください。

import React from 'react';

const NotFound = () => {
  return <div>お探しのページはありません。</div>;
};

export default NotFound;

Next.js14でネストされたルーティングを作成する

ちなみにネストされたルーティングも同じようにディレクトリ構成で作ります。

ブログなどコンテンツが多いページ、カテゴリーのあるページなどでは「https://localhost:3000/blogs/0001」のようにしたいわけです。

例えば以下のようにディレクトリ構成を作成して、各フォルダにはpage.tsxを配置します。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-blogs
    |   |-page.tsx
    |   |
    |   |-0001
    |   |  |-page.tsx
    |   |-0002
    |      |-page.tsx
    |-page.tsx
    |-layout.tsx 
import React from 'react';

const page = () => {
  return <div>ブログページ</div>;
};

export default page;
import React from 'react';

const page = () => {
  return <div>ID:0001</div>;
};

export default page;
import React from 'react';

const page = () => {
  return <div>ID:0002</div>;
};

export default page;

まずはhttps://localhost:3000/blogsにアクセスしてみます。

続いてblogs配下で作成していたディレクトリまでURLで移動してみます。

それぞれ親子関係になっているディレクトリのpage.tsxにアクセスすることができています。

一方で新規ページの追加、削除の頻度が多いケースだと毎回ディレクトリを作成したり削除することを手動でやらねばなりません。

そのような場合にNext.jsではparamsという仕組みを持っていて追加や削除が多くても簡易に運営できるようになっています。

以下のようなディレクトリ構成にしてみます。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-blogs
    |   |-page.tsx
    |   |
    |   |-0001
    |   |  |-page.tsx
    |   |-0002
    |      |-page.tsx
    |
    |-products
    |      |-page.tsx
    |      |
    |      |-[productId]
    |           |-page.tsx   
    |  
    |
    |-page.tsx
    |-layout.tsx 

新しくproductsというディレクトリを作成して[productId]という子供のディレクトリを持たせています。

ディレクトリ名を[]で囲むことがポイントです。

import React from 'react';

const page = () => {
  return (
    <div>
      <h1>商品一覧</h1>
      <p>商品A</p>
      <p>商品B</p>
      <p>商品C</p>
    </div>
  );
};

export default page;
import React from 'react';

const page = ({ params }: { params: { productId: string } }) => {
  console.log(params);
  return <div>商品名:{params.productId}</div>;
};

export default page;

[]で囲むことでその中にあるデータはparamsというpropsを使用できるようになります。

またparamsはオブジェクト形式になっています。

上記コードでconsole.logを書いておいたのでhttp://localhost:3000/product/0001にアクセスしてみます。

ターミナルにparamsの中身が表示されていて、オブジェクト形式でproductId: “0001”となっていることがわかります。

またブラウザも先ほどの手動でURLのクエリ名を使ったディレクトリを作成した時と同じような画面遷移ができています。

[]で囲んだディレクトリでは[プロパティ名]という意味になり、paramsのオブジェクトのプロパティ名として登録されます。

プロパティに対応する値はブラウザ上でURLのクエリ名になって、クエリ名が変わるたびにプロパティの値も動的に変わる仕組みです。

WordPressのようなCMSツールを扱ったことがあれば「スラッグ」に当たる部分になります。

この方法であればディレクトリを作成することを手動でやらなくても[]で囲んだディレクトリとpage.tsxさえ用意しておけばOKということです。

またparamsというprops自体はNext.js側で自動で生成されるのでconst params = {}というように宣言するコードを書く必要がない点も嬉しいです。

APIを取得してデータを表示する場合にはAPIのクエリをparamsのプロパティ名になると考えればAPIのクエリに連動した下層ページを動的に大量に作成することも可能になりますね。

また[]で囲んだディレクトリは子供のディレクトリを持ってネストさせることも可能です。

ディレクトリ構成を以下のように変更します。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-blogs
    |   |-page.tsx
    |   |
    |   |-0001
    |   |  |-page.tsx
    |   |-0002
    |      |-page.tsx
    |
    |-products
    |      |-page.tsx
    |      |
    |      |-[productId]
    |           |-reviews   
    |           |   |-[reviewId]
    |           |        |-page.tsx
    |-page.tsx
    |-layout.tsx 

[productId]の下にreviewsというフォルダを作成して、その下に[reviewsId]というフォルダを作成しています。

import React from 'react';
const page = ({
  params,
}: {
  params: {
    productId: string;
    reviewId: string;
  };
}) => {
  console.log(params);

  return (
    <div>
      商品ID:{params.productId}のレビューID:{params.reviewId}
    </div>
  );
};

export default page;

ネストされたので[]で囲まれたparamsのプロパティ名は2つに増えています。

こちらもconsole.logを入れているのでhttp://localhost:3000/products/0001/reviews/AAAというURLにアクセスしましょう。

ターミナルに表示されるparamsの中身が変わっていますね。

またブラウザの表示もできています。

スラッグ名が決まっていなかったり動的に追加、削除される可能性があるとき

ここまで紹介してきたディレクトリ名=スラッグ名にするルーティングは「スラッグ名が事前に決まっている」ことが前提となります。

例えばコーポレートサイトのお知らせ一覧ページを作成するとして、そのお知らせ一覧を年単位でまとめるのか月単位でまとめるのかは創業時には想像つかない顧客が多いのも現実です。

また日付を起点にしたルーティングをするにしても、未来はどこまでも続いていくのと過去はいくらでも遡れますのでディレクトリは追加もあれば削除もあり得るわけです。

そのような不確実性の高いコンテンツを運営するにあたりスラッグをどのようなキーワードでカテゴライズすれば良いのかわからないケースに合ったルーティングがNext.jsに用意されています。

先ほど紹介したものに少し似ていて[[…slug]]とすることで入れ子のディレクトリを好きなだけ追加したり削除しても問題なくできるようになります。

[productId]となっていた部分がスプレッド構文で…slugとなっていることから、配列の中身を自由に変更できるJavaScriptの特性を利用しているためです。

具体的には以下のようなディレクトリ構成にします。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-news
    |   |-[[...slug]]
    |        |-page.tsx
    |   
    |-page.tsx
    |-layout.tsx 

先ほどまで紹介していた方法も便利であることには変わりありませんが、事前にスラッグ名を決めてディレクトリ構成を用意する必要がありファイルの数に大きな差があることがわかります。

<これまでのディレクトリ構成>
src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-blogs
    |   |-page.tsx
    |   |
    |   |-0001
    |   |  |-page.tsx
    |   |-0002
    |      |-page.tsx
    |
    |-products
    |      |-page.tsx
    |      |
    |      |-[productId]
    |           |-reviews   
    |           |   |-[reviewId]
    |           |        |-page.tsx
    |-page.tsx
    |-layout.tsx 


ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー


<今から作るディレクトリ構成>
src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-news
    |   |-[[...slug]]
    |        |-page.tsx
    |   
    |-page.tsx
    |-layout.tsx 

/src/app/news/[[…slug]]/page.tsxについては以下のように書きます。

import React from 'react';

const page = ({ params }: { params: { slug: string[] } }) => {
  if (params.slug?.length === 2) {
    return (
      <h1>
        {params.slug[0]}年{params.slug[1]}月のお知らせ一覧です。
      </h1>
    );
  } else if (params.slug?.length === 1) {
    return <h1>{params.slug[0]}年のお知らせ一覧です。</h1>;
  } else {
    return <h1>お知らせ一覧です。</h1>;
  }
};

export default page;

お知らせ一覧を表示することには変わりませんがスラッグの数によって「/news/2024/01」のような年月でカテゴライズするのか、「/news/2024」のように年単位のみでカテゴライズするのか簡単にスイッチできるのです。

通常であればサイトを運営中にカテゴライズの方法を変更するにはDBの設定を変更したり、コードを大幅に変更したりなどしなければなりません。

現在コーポレートサイトを運営しているとして、まだ数件しかコンテンツがないときはカテゴライズする必要もないので「/news」として全て表示できます。

しばらくしてコンテンツの件数が増えてきたので年単位でカテゴライズして表示することも可能です。

さらに件数が増えてきて年単位だけでも煩雑になってきたら年月で細かくカテゴライズして表示することも可能です。

たった今作った短いコードを保存しておけば途中で大きなコード修正の必要なく動的にURLの運営方法を変更できるわけです。

従来の静的サイトやWordPressのようなCMSツールを使ったサイト構築を経験された方なら少し信じ難いかもしれませんね。

このようなバックエンド系の言語で取り入れられているルーティングの考え方をフロントエンドで使用できるようになっている点がNext.jsが支持されている理由です。

Next.jsでネストされたルーティングを作ってURLにフォルダ名を表示させたくない時

ネストするとURLがどんどん長くなっていきますので、途中の階層のディレクトリ名をURLから省略させたい時があります。

そのような時は「(ディレクトリ名)」と()で囲んだフォルダ名を命名すると、その配下にあるURLをルーティングに活用しつつ()で囲まれたフォルダ名をURLから削除することができます。

例えば以下のようなディレクトリ構成を作ったとします。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-news
    |   |-[[...slug]]
    |        |-page.tsx
    |   
    |-page.tsx
    |-layout.tsx 
    |
    |-auth
    |  |-login
    |  |   |-page.tsx
    |  |
    |  |-signup
    |  |   |-page.tsx
    |  |    
    |  |-signout
    |  |   |-page.tsx

loginフォルダのpage.tsxを表示するにはhttp://localhost:3000/auth/loginというURLになります。

そこでauthフォルダを以下のように「(auth)」と変更してみます。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-news
    |   |-[[...slug]]
    |        |-page.tsx
    |   
    |-page.tsx
    |-layout.tsx 
    |
    |-(auth)
    |  |-login
    |  |   |-page.tsx
    |  |
    |  |-signup
    |  |   |-page.tsx
    |  |    
    |  |-signout
    |  |   |-page.tsx

そうするとhttp://localhost:3000/loginだけでloginフォルダのpage.tsxにアクセスできるようになります。

逆にURLの中にauthを含めると404ページになります。

今回のようなauthというフォルダの中に複数の子ディレクトリがあるときはauthというスラッグは省略される方が良いとされています。

Next.jsで管理者だけに表示するプライベートフォルダを作る

続いてCMSのような管理者画面が必要な場合や、現在作成途中でまだ公開したくないページがあった時の運用について紹介します。

Next.jsはディレクトリによってURLのルーティングが決まることを前章までに解説しましたが、実は各フォルダのファイルはpage.tsxかpage.tsじゃないとユーザーから公開データとして確認できないようになっています。

例えば以下のようなフォルダを作ったとします。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-news
    |   |-[[...slug]]
    |        |-page.tsx
    |  
    |-page.tsx
    |-layout.tsx 
    |
    |-dashboard
    |    |-dashboard.tsx

dashboardフォルダの中にdashboard.tsxを作りましたが、http://localhost:3000/dashboardにアクセスしても404ページになります。

一方でdashboard.tsxをpage.tsxに変更すると読み込みが変わります。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-news
    |   |-[[...slug]]
    |        |-page.tsx
    |  
    |-page.tsx
    |-layout.tsx 
    |
    |-dashboard
    |    |-page.tsx

実はpage.tsxかpage.tsを公開するファイルとして読み込むような仕様になっているので、それ以外の名前にするとユーザーからは見えないページになるのです。

この特性を利用して管理者だけが確認できるページや未完成で非公開にしておきたい作業途中のページを運用することができるわけです。

ただしファイル名をpageにするかしないかだと運用ミスの原因に成りかねないので実務ではフォルダ名を「_〇〇」にすることでプライベートページとして運用することになります。

先ほどと同じく「_」から始まるURLスラッグはルーティングとして認識しないようになっているので同じくユーザーに見えないページを作ることができるのです。

先ほどのdashboardフォルダを_dashboardフォルダに変更します。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-news
    |   |-[[...slug]]
    |        |-page.tsx
    |  
    |-page.tsx
    |-layout.tsx 
    |
    |-_dashboard
    |    |-page.tsx

ファイル名はpage.tsxのままですがフォルダ名の先頭に「_」がついたことで再度404ページに変わりました。

Next.jsでテンプレート化した共通パーツを作るlayout.tsxについて

1つのページの中でもヘッダーやフッターなど共通化できるパーツがあります。

それらをコンポーネント化しても良いのですがReactにはchildrenというJSX記法で作られたパーツを他のコンポーネントにpropsで渡す仕組みがあります。

Next.jsではlayout.tsxというファイルが用意されており、その中で書かれたJSX記法はchildrenとなってpage.tsx以下の全てのコンポーネントで表示させることができます。

またlayout.tsxはプロジェクトの初期状態ですでに作られているので自分でファイル作成するのではなく中身を修正する形で作っていきます。

import { propagateServerField } from 'next/dist/server/lib/render-server';

export const metadata = {
  title: 'Next.js',
  description: 'Generated by Next.js',
};

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

現状だとreturnの中にHTMLの雛形があってbodyタグの間にchildrenがある状態です。

実はこのchildrenがすでに/src/app/page.tsxのことになっていて、Next.jsは最初の状態からchildrenを使ったJSX記法のpropsで運用されているわけです。

layout.tsxの中身を以下のように書き換えてみます。

import { propagateServerField } from 'next/dist/server/lib/render-server';

export const metadata = {
  title: 'Next.js',
  description: 'Generated by Next.js',
};

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
       {/* ここを追加 */}
        <header>
          <p>ヘッダーです</p>
        </header>
        {children}
       {/* ここを追加 */}
        <footer>
          <p>フッターです</p>
        </footer>
      </body>
    </html>
  );
}

/src/app/page.tsxは以下のようなファイルになっているにも関わらず「ヘッダーです」「フッターです」が追加されていますね。

import React from 'react';

const page = () => {
  return <div>page</div>;
};

export default page;

下層ページにもアクセスして見ましょう。

どの下層ページに行っても「ヘッダーです」「フッターです」が表示されていますね。

これがlayout.tsxで運用するテンプレート化のレイアウトになります。

また下層ページ専用のテンプレート化を作ることも可能です。

先ほどやった/src/app/layout.tsxの他に/src/app/products/[productId]/layout.tsxというファイルを新規作成します。

/src/app/layout.tsxは自動で作成されるのですが下層ページについては自分で作る必要があります。

import { propagateServerField } from 'next/dist/server/lib/render-server';

export const metadata = {
  title: 'Next.js',
  description: 'Generated by Next.js',
};

export default function ProductsLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <>
      <header>商品ページ専用のヘッダーです</header>
      {children}
    </>
  );
}

注意点としては下層ページでlayout.tsxを作る時にはreturnの中でHTMLの雛形は作らず空のフラグメントの中で書くことです。

/src/app/layout.tsxですでに<body>タグを作っているため、下層ページでも書くと<body>タグが2個できてしまうためです。

確認のためにトップページに戻ってみます。

トップページには「商品ページ専用のヘッダーです」が無くなっていますね。

このようにして条件分岐のようにテンプレートパーツを変えることができるのも特徴です。

Next.jsでtitleタグとメタディスクリプションを設定する方法

HTML構造のテンプレート化ができることがわかったところで、titleタグとメタディスクリプションの設定方法も紹介しておきます。

前章のlayout.tsxを使ってtitleタグとメタディスクリプションを設定することもできますし、ページごとのpage.tsxで設定することもできます。

一番簡単なのはlayout.tsxで設定する方法で、前章で説明した通りテンプレート化されるので個々のページに毎回設定しなくて良くなります。

またNext.jsをインストールした段階でlayouy.tsxにはmetadataという名前でデフォルトのダミーのテキストで設定がされているので、自分が表示させたいテキストに置き換えるだけで済みます。

import { propagateServerField } from 'next/dist/server/lib/render-server';

// ここが最初から書いてあるのでテキストだけ置き換えればOK
export const metadata = {
  title: 'Next.js',
  description: 'Generated by Next.js',
};

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

定数metadataはオブジェクト形式になっていてtitleプロパティにはtitleタグのテキストを、descriptionプロパティにはメタディスクリプションのテキストを入れればOKです。

一方でページごとにテキストを変えたいときは対象のpage.tsxの中で以下のように書きます。

page.tsxで設定されている場合はlayout.tsxに設定があったとしてもpage.tsxに書かれた内容に上書きされる仕組みになっているからです。

import React from 'react';

export const metadata = {
  title: 'アバウトページです',
  description: '説明文です',
};

const page = () => {
  return <div>About</div>;
};

export default page;

http://localhost:3000/aboutにアクセスしてみるとtitleタグとメタディスクリプションが変わっていることが確認できます。

逆に他のスラッグにアクセスしてみるとlayout.tsxの内容のままになっています。

全てのページで統一するのか、部分的に変更しておくのかはサイトの運営によって変わります。

ちなみにサイト運営の中でtitleタグとメタディスクリプションの文章がパターン化することがあります。

そのような目的でlayout.tsxを以下のように書くこともできるようになっています。

以下のコードはtitleプロパティをオブジェクト形式にして選択肢のような書き方にしました。

defaultプロパティがデフォルトのテキストで、templateプロパティには「%s」という各ページによって動的にテキストを変更できる特殊文字を入れることができます。

またオブジェクト形式を使うにはMetadataという型を指定することになっています。

// ここを追加
import { Metadata } from 'next';
import { propagateServerField } from 'next/dist/server/lib/render-server';

// ここを変更
export const metadata: Metadata = {
  title: {
    default: 'デフォルトです',
    template: '%sです',
  },
  description: 'Generated by Next.js',
};

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

特に指定がなければdefaultの値が全てのページに反映されて各ディレクトリのpage.tsxに設定はいりません。

「特定のページについてはテキストを変えたい」「テキストをパターン化して運用をしやすくしたい」という場合には、テキストを変更したいpage.tsxで以下のように書きます。

// ここを追加
import { Metadata } from 'next';
import React from 'react';

// ここを変更
export const metadata: Metadata = {
  title: 'アバウトページ',
  description: '説明文です',
};

const page = () => {
  return <div>About</div>;
};

export default page;

Metadataという型を指定することでlayout.tsxのtemplateプロパティの内容を利用できるようになります。

titleプロパティの最初の例では「アバウトページです」としていましたが、「〇〇です」というパターン化した運用が予測される場合には〇〇の部分だけをpage.tsxで差し替えることにできます。

layout.tsxで雛形を作っておいて、動的に変更される部分だけをそれぞれのpage.tsxで記載する方法です。

またテキスト変更しなくて良いページのpage.tsxには何も書かなければ、layout.tsxのdefaultプロパティの内容が自動的に表示されます。

このような柔軟な運営に対応できる仕組みを持っていることもNext.jsの魅力です。

Next.jsでリンクタグを表示する方法

ここまではルーティングの設定を中心に解説してきましたので、画面遷移はURLの直接変更をしていました。

実際にはボタンを設置してクリックされたら画面が移動することが好ましいので、いわゆるリンクタグの表示方法について紹介していきます。

Next.jsにおいてリンクタグを表示するにはLinkというコンポーネントが担当します。

import React from 'react';
// インポート(クリックによって移動できるようにする)
import Link from 'next/link';

const page = () => {
  return (
    <div>
      page
      {/* ここを追加 */}
      <Link href="/about">会社概要</Link>
    </div>
  );
};

export default page;

LinkタグはHTMLのaタグを自動で出力するためのコンポーネントでhref属性にルートからのパスを指定します。

検証ツールを確認するとaタグが表示されているのがわかります。

これで「会社概要」をクリックすると/aboutに画面遷移できるようになりました。

一方でダイナミックルーティングを使用しているページについてもリンクタグを設置するのですが方法が少し変わります。

例えば以下のような/productsについてダイナミックルーティングが設定されている状態だとします。

src
 |-app 
    |-about
    |   |-page.tsx  
    |
    |-contact
    |   |-page.tsx
    |
    |-blogs
    |   |-page.tsx
    |   |
    |   |-0001
    |   |  |-page.tsx
    |   |-0002
    |      |-page.tsx
    |
    |-products
    |      |-page.tsx
    |      |
    |      |-[productId]
    |           |-reviews   
    |           |   |-[reviewId]
    |           |        |-page.tsx
    |-page.tsx
    |-layout.tsx 

/productsより下層のページに行くとして、ディレクトリ名でパスを指定していないので明示的なパス指定ができません。

その場合には以下のように書きます。

import React from 'react';
// インポート
import Link from 'next/link';

const page = () => {
  return (
    <div>
      <h1>商品一覧</h1>
      {/* []でルーティングを構成しているとき(APIなどidが動的に変わる想定) */}
      <p>
        <Link href="products/1111">
          商品B
        </Link>
      </p>
      <p>商品C</p>
    </div>
  );
};

export default page;

実際にはAPIなどで動的にIDが変わる想定ですが下層ページに行くにはIDを指定することになります。

またこのように下層ページにどんどん遷移していった時に一気にトップページに戻りたい時があります。

その場合にはreplace属性をつけておくことでブラウザバックにより一気にトップページに戻ります。

通常は以下のように1ページずつブラウザバックで戻っていきます。

replace属性を追加しておくことでブラウザバックで一気にトップページまで戻ることができます。

import React from 'react';
// インポート
import Link from 'next/link';

const page = () => {
  return (
    <div>
      <h1>商品一覧</h1>
      {/* replaceを設定するとブラウザバックで商品一覧を飛ばしてトップページにまで飛ぶことが可能 */}
      <p>
        <Link href="products/1111" replace>
          商品B
        </Link>
      </p>
      <p>商品C</p>
    </div>
  );
};

export default page;

さらに画面遷移したときに合わせて関数などのコードを実行したい時があります。

Next.jsにはuseRouterというフックがあり、画面遷移にあわせて関数を実行することができるようになっています。

import React from 'react';
// ここを追加
'use client';
// ここを追加
import { useRouter } from 'next/navigation';
import Link from 'next/link';

const page = () => {
  // ここを追加
  const router = useRouter();
  const handleClick = () => {
    console.log('注文送信');
    router.push('/');
  };

  return (
    <div>
      <h1>商品一覧</h1>
      <p>
        <Link href="products/1111" replace>
          商品B
        </Link>
      </p>
      <p>商品C</p>

      {/* ここを追加 */}
      <h1>ご注文内容</h1>
      <button onClick={handleClick}>注文</button>
    </div>
  );
};

export default page;

useRouterはブラウザで使うものになっているのですがNext.jsはサーバーサイドでも機能を持たせられるのでページの先頭にuse clientというコードを書いて「ブラウザで実行」することを明記しておく必要があります。

あとはインポートしてインスタンス化すればReactフックのように使用できます。

useRouterにはpushというメソッドがあり画面遷移を担当していますので、onClickイベント時の関数の中で特定の処理が終わったらrouter.push(パス)を書くことで画面遷移も一緒に実行できるわけです。

Next.js14でオリジナルのローディング画面を作る方法

Next.js自体が読み込みが早く動作するようになっているのですが、オリジナルのローディング画面を差し込むこともできます。

ローディングを挟みたいページのディレクトリ直下にloading.tsxというファイル名でファイルを作成して、その中でローディング画面をコーディングするだけです。

import React from 'react';

const loading = () => {
  return <div>ローディング中。。。</div>;
};

export default loading;

各ページのディレクトリに作ってそれぞれ別のデザインのローディング画面を表示することもできますし、ローディングが必要ないところではページのディレクトリにloading.tsxを作らなければOKです。

Next.js14でオリジナルのエラー画面を作る方法

またエラー画面もオリジナルで作ることが可能です。

エラー画面も表示させたいページのディレクトリ直下にerror.tsxというファイル名で作成して、エラー画面の内容をコーディングするだけです。

1点注意点としてはNext.js自体がサーバーとフロントの両方の機能を持っており、エラーをどちらで出すか明示しないといけない点です。

画面としてエラーを出すのであればerror.tsxを作った上で一番上に「use client」と書くことになります。

// クライアントで使うファイルのため
'use client';
import React from 'react';

const Error = () => {
  return <div>読み込みエラーです</div>;
};

export default Error;

また今回参考にした書籍は以下になります。

よければどうぞ。

  • このエントリーをはてなブックマークに追加