前書き、概要
プログラミング学習中に、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
にすべきではないのか??と。上記のように変更すると、無事ページ遷移に成功しました。
まとめ
ずっとできなかった動的ルーティング。もしかすると、他の解決方法があるかもしれません。他にも調べてできたら、追記していこうと思います。