【Next.js】getStaticPropsでJSON一覧から個別情報を取得するメモ
概要
前回、Next.jsでJSONファイルなど情報を取ってくる方法としてgetServerSidePropsについて防備ログとして記事にしたが、今度はgetStaticPropsの場合について。
基本的には前回のgetServerSidePropsと記事の内容は同じなので、体裁は変わってない部分もある。
最終目的
最終的な目的として、以下のことを最終目的とする。
前回の記事のgetStaticPropsバージョンとする。
- jsonファイルからデータを取得して一覧表示する
- 一覧をクリックしたら個別ページにその情報を表示する
getStaticPropsとは?
getStaticPropsとはビルド時にデータを取得して事前にHTMLファイルのレンダリングを行うことでSSGとも呼ばれてる。
getServerSidePropsのようにリクエスト毎にレスポンスを返さないので高速だが、リアルタイム性が要求される場面では、getServerSidePropsを使ってデータを読み込む必要があるなど、状況によって使い分ける必要がある。
Next.jsでプロジェクトを作成すると「pages」ディレクトリが作成されるのですがgetServerSidePropsもgetStaticPropsも「pages」ディレクトリ以外は使えない。
実際の流れ
では、実際の流れをメモしていく。
基本的に前回と同様だが、流れを意識したいので同じ流れをもう一度。
JSONを読み込んで一覧ページを作成
実際に読み込み処理を書きます。以下のJSONファイルを読み込みます。
今回はユーザーのデータを表示したいので、以下のJSONファイルを読み込むことにする。
https://jsonplaceholder.typicode.com/users
//一人のユーザーのスキーマは以下のようになってる
{
"id": 2,
"name": "Ervin Howell",
"username": "Antonette",
"email": "Shanna@melissa.tv",
"address": {
"street": "Victor Plains",
"suite": "Suite 879",
"city": "Wisokyburgh",
"zipcode": "90566-7771",
},
},
JSONファイルを読み込む
JSONファイルを読み込む処理、今回はpagesフォルダにusersフォルダを作成して、そこにindex.jsを作成するものとする。
export default function Users(data) {
return (
<div>
<h1>【Next.js】getStaticPropsでJSONファイルを一覧表示</h1>
</div>
)
}
export const getStaticProps = async () => {
const res=await fetch("https://jsonplaceholder.typicode.com/users")
const users=await res.json()
return {
props:{users}
}
}
getStaticProps はHome()の外でexportを利用して使用する。
getStaticProps 内でfetch()で取得したデータからJSONを取得しDOM操作に利用する必要があるので、getServerSidePropsにasyncを付けて、fatch()とres.json()にはawaitをつけて非同期処理で取得。
その結果を返してあげる必要があるので、return{}でpropsプロパティにオブジェクトでデータを渡す。
JSONファイルを表示する
今度は取得したJSONファイルを表示する必要がある。
import Link from 'next/link'
export default function Users(data) {
return (
<div className="wrapper">
<h1>ユーザー一覧を表示</h1>
<ul>
{data.users.map((user)=>{
return(
<ll key={user.id}>
<Link href={`/users/user/${user.id}`}>
<a>
<p>名前:{user.name}</p>
<p>E-MAIL:{user.email}</p>
<p>住んでる街:{user.address.city}</p>
</a>
</Link>
</ll>
)
})}
</ul>
</div>
)
}
JSONファイルはgetStaticPropsのpropsに渡したデータは、Users(data)に引数から受け取ることができる。プロパティ名をdataとしているがなんでもいい。
その後、map関数で各データを取り出して表示。
ちなみに、data.usersの「users」という名前は、getServerSideProps のprops: { users }で渡している変数名。
またルーティング用のコンポーネントであるLINKには、JSONファイルには各ユーザーの「id」があったのでhrefに設定しておきます。hrefのパスの階層は後に作成する個別ファイル([id].js)と同じ階層にする。
この「id」番号は各ユーザー詳細のファイルで再度fetch()で読み込む際に必要となります。
個別ページを作成・表示
一覧ページを作成したら今度は個別ページを作成します。
個別ページでも同様に、getStaticPropsを利用します。
個別ファイルを作る
今回はpages/users/user/[id].jsとしたいので、usersディレクトリにuserフォルダを作成してそこに[id].jsを作成。
[id].jsにも同様に、getStaticPropsの処理を記載します。getServerSidePropsの時と処理は同じで引数にcontextを指定する。
export const getStaticProps=async (context)=>{
console.log(context)
const id=context.params.id
const res=await fetch(`https://jsonplaceholder.typicode.com/users/${id}`)
const user=await res.json()
return{
props:{user}
}
}
console.log(context)で確認するとわかるが、このcontextにいろんな情報が格納されている。
今度はユーザー一覧ではなく、各ユーザーのデータが欲しいので、JSONファイルから各ユーザーの「id」を指定したURLからfetch()による非同期処理で取得する。
各の「id」番号がcontextのparamsの中にid番号が入ってる。
params: { id: '1' },
この「id」は一覧ページでhref属性に設定した各ユーザーの「id」番号である。
ちなみに今回[id].jsとファイル名を指定しているが、[post].jsだった場合は、contextのparamsは以下になる。
params: { post: '1' },
あとは同様にpropsに各ユーザーのデータを指定してreturnしてあげる。
contextからidを取得する際の注意点
getServerSidePropsの場合は、contextからidを取得する場合は、'query'(クエリパラメータ)かparamsから取得していました。
export const getStaticProps=async (context)=>{
const id=context.params.id
}
getStaticPropsの場合は、query(クエリパラメータ)は存在せず、paramsになるので注意する。
getStaticPathsでパス情報の取得する
これまではgetServerSidePropsと同じ処理だが、個別ページへのパスはgetStaticPropsと違ってgetStaticPathsを利用してreturnで返してあげる必要がある。
export const getStaticPaths = async () => {
const res=await fetch("https://jsonplaceholder.typicode.com/users")
const users=await res.json()
const paths = users.map((user) => ({
params: { id: user.id.toString() },
}))
return {
paths,
fallback:false
}
}
fetch()で各ユーザーのURLパスを取得したいので、ユーザ一覧のJSONのURLを指定する。
取得した後は、map()で各ユーザーのid番号を変数pathsにretrunで返してあげる。
その際、以下のようにparamsのプロパティに以下のように指定してあげる。
params: { id: user.id.toString() },
toString()としてるのは、こちらのidはgetStaticPropsでJSONファイルを読み込む時のidが文字列だから。
また、pathsとparamsという名前は決まってるので変更しないこと。他の名前にするとエラーがidが取得できずエラーが出る。
取得したパスをconsoleで確認すると以下のような配列で取得できる。
[
{ params: { id: '1' } },
{ params: { id: '2' } },
{ params: { id: '3' } },
{ params: { id: '4' } },
{ params: { id: '5' } },
{ params: { id: '6' } },
{ params: { id: '7' } },
{ params: { id: '8' } },
{ params: { id: '9' } },
{ params: { id: '10' } }
]
fallbackの設定
fallbackはfalseに設定すると存在しなページの場合は404エラーが表示されます。

fallbackはtrueに設定すると存在しなページの場合はサーバーエラーが表示されます。

各ユーザーの内容を表示する
こちらは一覧ページと同じである。
分割代入で{user}から各ユーザーの名前などを表示させている。
export default function User({user}) {
return (
<div className="wrapper">
<h1>ユーザーID:{user.id}</h1>
<p>名前:{user.name}</p>
<p>E-MAIL:{user.email}</p>
<p>住んでる街:{user.address.city}</p>
</div>
)
}
個別ページの名前とパラメーター名との関連性
Next.js では、個別ページのファイル名を[param] のようにして角括弧([])を使って動的なルーティングに対応することができるが、getStaticPropsで個別の内容を表示させる方法を調べてファイル名とパラメータ名の関連性に気が付いた点が以下。
詳細ページのファイル名を[test].jsとした場合、
getStaticPathsで取得したparams: { test: user.id.toString() }と
getStaticPropsでcontextから取得するconst id=context.params.testといったように
「test」という名前とパラメータ名を一致させないとエラーがでる。
これは、getServerSidePropsで個別ページを作成する場合も同様。
参考サイト
Discussion