Next.js - ダイナミックルーティング
背景
実務ではReactを使っているのですがNext.jsのキャッチアップしておきたいと思ったので、その内容を整理したいと思います。
本記事では、Next.jsに関する情報をまとめています。
内容は易しめです。
前回の続きになります!
ダイナミックルーティング
静的パスのルーティング
Next.jsでは、フォルダーとファイルの名前で自動的にパスが割り当てられます。
pages/blog/post.tsx
というファイルを作成した場合、/blog/post
にアクセスすることで、そのコンポーネントが表示されるようになります。
静的パスでは動的パスに対応できない
**/data/01とすると1番目のデータが表示される**
といったようなページのURLにパラメータが含まれるような動的パスに対応するには、本来ならば「data」フォルダー内に「1.js」というファイルとして用意しないといけません。
ただ、上記のようなやり方ではアプリケーションが成り立ちませんね。
Next.jsでは動的パスに対応するためのダイナミックルーティング
という機能が用いられます。
ダイナミックルーティング
ダイナミックルーティングでは、以下でいう[post]のように配列の的な変数値を任意のファイル名で定義するイメージです。
pages/ ├── index.tsx ├── about.tsx ├── [post].tsx
動的なURLにアクセスされたときに、[post].tsxファイルが呼び出されます。
このファイル内で、アクセスされたURLに含まれるパラメータを取得して、それに基づいてページをレンダリングすることができます。
使用してみる
Next.jsに用意されている「useRouter」という機能を使います。
import { useRouter } from 'next/router'
useRouterは、以下のようにしてrouter
オブジェクトを作成して利用します。
const router = useRouter()
このrouter
からパラメータの情報を取り出し利用します。
[]を使ってパラメータに設定された値は、router.queryというプロパティにまとめられています。
routerオブジェクト
routerオブジェクトの中身は以下のようになっていました。
router
オブジェクトは、Next.jsアプリケーション内でのページ遷移やクエリパラメータの取得などに使われます。
以下は一部を抜粋した解説表になります。
名称 | 説明 |
---|---|
pathname | 現在のURLのパス部分を取得する。 |
query | クエリパラメータを含むオブジェクトを取得する。 |
asPath | ユーザーがアクセスしているURLを取得する。 |
push | ページ遷移する。 |
replace | 現在のページを別のページに置き換える。 |
back | 前のページに戻る。 |
prefetch | データを事前に取得し、キャッシュする。 |
isReady | ページの読み込みが完了したかどうかを取得する。 |
route | 現在のURLのパス部分を取得する。 |
basePath | ベースパスを取得する。 |
isFallback | フォールバックの状態を取得する。 |
router.(push / repace / reload) - ページ遷移の制御
push
, replace
, reload
メソッドを活用すると、ブラウザの履歴を操作しつつページ遷移を制御することができます。
ブラウザの履歴を操作しながら「次のページ」に遷移する例 - push
import { useRouter } from 'next/router' function handleClick() { const router = useRouter() router.push('/next-page') }
ブラウザの履歴を上書きして、前のページに戻れなくする例 - **replace**
import { useRouter } from 'next/router' function handleClick() { const router = useRouter() router.replace('/next-page') }
現在のページをリロードする例 - reload
import { useRouter } from 'next/router' function handleClick() { const router = useRouter() router.reload() }
router.isReady - 初期化の完了確認
Next.jsのuseRouter
フックで取得できるrouter
オブジェクトは、初期化が完了するまで情報が入っていないため、isReady
プロパティを使用して初期化が完了したことを確認する必要があります。
useEffect(()=>{ if(!router.isReady) return // router.queryから値を取得し処理を行う }, [router.isReady]);
動的パスの実装例
動的なURLに遷移したときに対応するコンポーネントを実装した例を紹介します。
遷移元 - src/pages/**index.tsx**
下記のコードではAPIで取得したデータリストのそれぞれの要素に対応するデータの詳細ページへのリンクを「 show detail. 」を表示させます。
// src/pages/index.tsx ...略... {sampleData.map((item, index) => ( <div key={index} className="alert alert-info my-3"> <p className="h5">msg: "{item.text}".</p> <p className="h6">by {item.author}. ({item.email})</p> <Link href={`/data/${index + 1}`} as={`/data/${index + 1}`} passHref> show detail. </Link> </div> ))} ...略...
リンクの URL は、 /data/[num]
として指定されており、実際の URLは/data/1
、/data/2
、/data/3
... となります。
遷移先 - src/pages/data/**[num].tsx**
このコードは/data/:num
という動的パスのページを表示させるpageコンポーネントです。
このファイル自体が遷移先としてのページの内容を記述しています。
パス中の:num
は、実際のアクセス時に指定された数値に置き換えられます。
fetchSampleData
を使用してデータを取得した後、現在のページへのアクセス情報とともに、対応するデータを選択します。
// src/pages/data/[num].tsx import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import fetchSampleData from '../api/sample'; type Data = { text: string; author: string; email: string; }; const DataDetail = () => { const [sampleData, setSampleData] = useState<Data[]>([]); const [selectedData, setSelectedData] = useState<Data | null>(null); const router = useRouter(); const { num } = router.query; const [isLoading, setIsLoading] = useState(true); // ローディング状態を管理する useEffect(() => { const getData = async () => { const json = await fetchSampleData(); setSampleData(json); }; getData(); }, []); useEffect(() => { if (num && sampleData.length > 0) { const index = Number(num) - 1; setSelectedData(sampleData[index]); setIsLoading(false); // データの読み込みが完了したらローディングを解除する } }, [num, sampleData]); if (isLoading) { // ローディング中はコンポーネントを表示しない return <div>Loading...</div>; } return ( <main className="container"> <h2 className="my-4">Data Detail page.</h2> {selectedData ? ( <div className="alert alert-primary"> <table className="table"> <thead> <tr> <th>Text</th> <th>Author</th> <th>Email</th> </tr> </thead> <tbody> <tr> <td>{selectedData.text}</td> <td>{selectedData.author}</td> <td>{selectedData.email}</td> </tr> </tbody> </table> </div> ) : ( <div className="alert alert-danger">No data found.</div> )} </main> ); }; export default DataDetail;
続く…
コメント
本記事の内容は以上になります!
続きのアウトプットも随時更新したいと思います。
間違いがありましたら修正いたしますので、ご指摘ください。
興味があれば他の記事も更新していきますので是非ご覧になってください♪
プログラミングスクールのご紹介 (卒業生より)
お世話になったプログラミングスクールであるRUNTEQです♪
こちらのリンクを経由すると1万円引きになります。
RUNTEQを通じて開発学習の末、受託開発企業をご紹介いただき、現在も双方とご縁があります。
もし、興味がありましたらお気軽にコメントか、TwitterのDMでお声掛けください。