LoginSignup
2
0

Next.jsの動的ルーティングについて

Last updated at Posted at 2024-01-28

前書き、概要

プログラミング学習中に、Next.js、Laravelを使用してRealWorldを作成しました。
その際、動的ルーティングに詰まったので忘れないように記録しておきます。
同じように詰まっている方の参考になれば幸いです。

使用バージョン

Next.js 14.1.0

目次

動的ルーティングとは
失敗例
解決した方法
まとめ

動的ルーティングとは

・リンク先のURLが正確に分からない
・もしくは渡されるパラメータによって表示する内容を変える
など動的なデータからルートを作成したい場合に対応できる機能。

設定方法

Next.jsリファレンスより

For example, a blog could include the following route pages/blog/[slug].js where [slug] is the Dynamic Segment for blog posts.

import { useRouter } from 'next/router'

export default function Page() {
 const router = useRouter()
 return <p>Post: {router.query.slug}</p>
}
Route Example URL params
pages/blog/[slug].js /blog/a { slug: 'a' }
pages/blog/[slug].js /blog/b { slug: 'b' }
pages/blog/[slug].js /blog/c { slug: 'c' }

つまり、[任意のファイル名].tsx(.jsでもOK)とすることで、[slug].tsxという1つのファイルで/blog/a,/blog/b,/blog/cなど様々なルートをキャッチできるということです。
加えて、その任意のファイル名をキーとして、値を取得・利用することもできます。とっても便利で簡単ですね。
しかし、私は全くうまくいきませんでした。

失敗例

Next.js/app/page.tsx(省略したもの)

"use client"
import Link from "next/link";
import React, { useState, useEffect } from 'react';

export default function Home() {
  const [articles, setArticles] = useState(null);
    const fetchArticles = async () => {
    try {
      const res = await fetch(`APIエンドポイントを記入`)
      const data = await res.json();
      setArticles(data);

    } catch (error) {
      console.error('Error:', error);
    }

  };

  useEffect(() => {
    fetchArticles();
  }, []);

  return (
    <>
      <div className="article-preview">
        <div className="article-meta">
          <Link href="/profile/{user_name}">
            <img src="http://i.imgur.com/Qr71crq.jpg" />
          </Link>
          <div className="info">
            <Link href="/profile/{user_name}" className="author">
              {article.user.name}
            </Link>
            <span className="date">{article.created_at}</span>
          </div>
          <button className="btn btn-outline-primary btn-sm pull-xs-right">
            <i className="ion-heart" /> 29
          </button>
        </div>
        <Link
          href={`/article/${article.id}`} //問題の部分
          className="preview-link"
        >
          <h1>{article.title}</h1>
          <p>{article.summary}</p>
          <span>Read more...</span>
          <ul className="tag-list">
            <li className="tag-default tag-pill tag-outline">{article.tagList}</li>
          </ul>
        </Link>
      </div>
    </>
  );
}

この<Link href={\/article/${article.id}`} className="preview-link">`で、APIから取得してきたデータIDをリンク先のURLに含めました。ここは動的に変わる部分。つまり先ほどの動的ルーティングの出番です。
わたしは以下のような構造にしました。

app
├ page.tsx
└ article(ディレクトリ)
  └ [id].tsx

これで、article/以下がどうなっていても上手くいくはず。しかし、結果は404エラー。「ページあるよ!!」と思っていました。

解決した方法

色々調べてみたところ、失敗例のようにファイル名を[]にする人の他、ディレクトリ名を[]にしている人がいました。

追記(2024.1.29)

色々調べてみたところ、失敗例のようにファイル名を[]にする人の他、ディレクトリ名を[]にしている人がいました。

についてコメント頂いた内容を記載。

Pages Router では、/pages ディレクトリ内の決まった拡張子のファイルすべてがページのコンポーネントになり得ましたが、
App Router では、/app ディレクトリ内の各ディレクトリの中にある /page.tsx のようなファイルだけがページのコンポーネントになります。
/app と /pages でファイル名についての規約が異なる、ということになります。

できると思っていた[〇〇].tsxは/appではページコンポーネントとしてみなされず、エラーが出ていたようです。

現在、Next.jsでは以下のようにルーティングがされています

app
├ page.tsx
└ dashboard(ディレクトリ)
  └ page.tsx

app/page.tsxはURLでは/app/dashboard/page.tsxはURL/dashboardで参照されます。そこでふと思いました。
先ほどの失敗例のように/article/${article.id}で接続したいなら、

app
├ page.tsx
└ article(ディレクトリ)
  └ [id](ディレクトリ)
      └ page.tsx

にすべきではないのか??と。上記のように変更すると、無事ページ遷移に成功しました。

まとめ

ずっとできなかった動的ルーティング。もしかすると、他の解決方法があるかもしれません。他にも調べてできたら、追記していこうと思います。

2
0
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0