📘

【Next.js】getStaticPropsでJSON一覧から個別情報を取得するメモ

2022/05/22に公開

概要

前回、Next.jsでJSONファイルなど情報を取ってくる方法としてgetServerSidePropsについて防備ログとして記事にしたが、今度はgetStaticPropsの場合について。

https://zenn.dev/kiriyama/articles/01bc41f7495a42

基本的には前回のgetServerSidePropsと記事の内容は同じなので、体裁は変わってない部分もある。

最終目的

最終的な目的として、以下のことを最終目的とする。
前回の記事のgetStaticPropsバージョンとする。

  • jsonファイルからデータを取得して一覧表示する
  • 一覧をクリックしたら個別ページにその情報を表示する

getStaticPropsとは?

getStaticPropsとはビルド時にデータを取得して事前にHTMLファイルのレンダリングを行うことでSSGとも呼ばれてる。

getServerSidePropsのようにリクエスト毎にレスポンスを返さないので高速だが、リアルタイム性が要求される場面では、getServerSidePropsを使ってデータを読み込む必要があるなど、状況によって使い分ける必要がある。

Next.jsでプロジェクトを作成すると「pages」ディレクトリが作成されるのですがgetServerSidePropsgetStaticPropsも「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を作成するものとする。

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}
  }
}

getStaticPropsHome()の外でexportを利用して使用する。
getStaticProps 内でfetch()で取得したデータからJSONを取得しDOM操作に利用する必要があるので、getServerSidePropsasyncを付けて、fatch()res.json()にはawaitをつけて非同期処理で取得。

その結果を返してあげる必要があるので、return{}propsプロパティにオブジェクトでデータを渡す。

JSONファイルを表示する

今度は取得したJSONファイルを表示する必要がある。

pages/users/index.js
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ファイルはgetStaticPropspropsに渡したデータは、Users(data)に引数から受け取ることができる。プロパティ名をdataとしているがなんでもいい。
その後、map関数で各データを取り出して表示。
ちなみに、data.usersの「users」という名前は、getServerSidePropsprops: { 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を指定する。

pages/users/user/[id].js

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」番号がcontextparamsの中に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から取得していました。

pages/users/user/[id].js
export const getStaticProps=async (context)=>{
  const id=context.params.id
}

getStaticPropsの場合は、query(クエリパラメータ)は存在せず、paramsになるので注意する。

getStaticPathsでパス情報の取得する

これまではgetServerSidePropsと同じ処理だが、個別ページへのパスはgetStaticPropsと違ってgetStaticPathsを利用してreturnで返してあげる必要がある。

pages/users/user/[id].js
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が文字列だから。
また、pathsparamsという名前は決まってるので変更しないこと。他の名前にするとエラーが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の設定

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

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

各ユーザーの内容を表示する

こちらは一覧ページと同じである。
分割代入で{user}から各ユーザーの名前などを表示させている。

pages/users/user/[id].js

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() }
getStaticPropscontextから取得するconst id=context.params.testといったように
「test」という名前とパラメータ名を一致させないとエラーがでる。
これは、getServerSidePropsで個別ページを作成する場合も同様。

参考サイト

https://nextjs.org/docs/basic-features/data-fetching/get-static-props
https://nextjs.org/docs/basic-features/data-fetching/get-static-paths
https://zenn.dev/yumiyoshi/scraps/f6220f26263103

Discussion