【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