7839

雑草魂エンジニアブログ

【Next】getInitialProps・getStaticProps・getStaticPaths・getServerSideProps の使い方まとめ

Next.js で開発しているときに、getInitialProps・getStaticProps・getStaticPaths・getServerSideProps について、いつ、どのように使うべきか、きちんと整理できておらず、自分なりの整理をしてみた。

今回整理する API は、どれもページコンポーネントで、プリレンダリングをしてデータを取得(フェッチ)する際に使用するものである。getInitialProps は「リクエスト時」にデータを取得する。そして、v9.3 から用途に応じて、より宣言的に書くことができるよう、以下の3つが追加された。

  • SSG用のAPI
    • getStaticProps(「ビルド時」にデータを取得する)
    • getStaticPaths(データに基づいて動的ルーティングを指定する)
  • SSR用のAPI
    • getServerSideProps(「リクエスト時」にデータを取得する)

SSR・SSGに関しては、前回の記事で整理したので、参考にしてほしい。

serip39.hatenablog.com

getInitialProps

公式ドキュメント:getInitialProps

getInitialProps はページがレンダリングされる前に実行される API である。関数名が、get(=得る)Initial(=初期の)Props(=プロパティ) となっている通り、ページに必要な初期のデータを props としてページコンポーネントに渡す役割がある。

そのため、getInitialProps は、SSR 時にはサーバー側でのレンダリング時に実行される。ただし、next/link を使用して、クライアントサイドでルーティングした場合にはクライアント側でも実行されるので注意が必要である。また、pagesフォルダ内のファイルのみで使用することができる。

v9.3以降は、getInitialProps は、getStaticProps or getServerSideProps で代用できるので、そちらの使用が推奨されている。(ただし、pages/_app.js では、getInitialProps しか使えないようだ。)

const PageComponent = (props) => {
  return <div>Next stars: {stars}</div>
}
PageComponent.getInitialProps = async (ctx) => {
  const isServer = !!ctx.req
  if (isServer) {
    // サーバーだけでの処理はここに記述する
  }
  // APIなどを用いてデータを取得する
  return { props: data } //シリアル化される
}
export default PageComponent

また、 pages/_app.tsx で使用する場合は、以下のようにして context を得るときに、appProps.pageProps を使う必要があるので注意。

const MyApp = ({ Component, pageProps }) => {
  return <Component {...pageProps} />
}
MyApp.getInitialProps = async (appContext) => {
  const appProps = await App.getInitialProps(appContext)
  const { ctx } = appContext
  if (isServer) {
    // サーバーだけでの処理はここに記述する
  }
  // APIなどを用いてデータを取得する
  appProps.pageProps = { ...appProps.pageProps, newData }
  return { ...appProps }
}
export default MyApp

Advanced Features: Custom `App` | Next.js

getStaticProps(For SSG)

公式ドキュメント:getStaticProps

getStaticProps は SSG 用の API である。そのため、getInitialProps はリクエスト時に毎回実行されていたが、getStaticProps の場合はビルド時のプリレンダリングで実行され、静的ファイルが事前に生成される。ビルド時に実行されるため、getStaticProps は必ずサーバーサイドで実行される。また、静的ファイルが生成された際には、HTML と JSON ファイルが生成される。この JSON ファイルは、next/linkを用いてクライアントサイドでルーティングを行った際に使用される。Next.js がこの JSON ファイルを取得して、ページコンポーネントに props として受け渡している。

export const getStaticProps = async ({ params, preview, previewData }) => {
  // headless CMSからデータを取得する
  return {
    props: {}, // will be passed to the page component as props
  }
}

また、開発時や下書きを作成する際に、毎回ビルドしてページを生成して確認するのは時間がかかりすぎてしまうため、「プレビューモード」という機能が備わっている。(完全にヘッドレスCMS向けに作られた機能である。)プレビューモードでは、静的生成ロジックをうまく利用して SSR を行い、プレビューを実現している。

Advanced Features: Preview Mode | Next.js

getStaticPaths(For SSG)

公式ドキュメント:getStaticPaths

getStaticPaths は、SSG 用の API であり、動的ルーティングの利用時に静的なファイルを生成する。

動的ルーティング(Dynamic Routes)とは、 /pages/user/[userId] のように [] でパラメータ名を囲い定義し、パラメータに応じて、動的に変化するルーティングを指す。

静的ファイルを生成する際に、動的ルーティングに対して、どのようなパラメータを設定して生成すべきかを getStaticPaths で定義する。そのため、以下の2つの設定が必須となっている。

  • paths : ビルドすべきパスを指定する
  • fallback : 該当しないパスへのアクセスがあった場合の動作の設定
    • falseの場合、「404」を表示する
    • trueの場合、以下のフローでページが表示される
      1. データが取得されるまで、Fallbackページが表示される
      2. サーバー側で、Next.jsがリクエストされたパスの静的ファイル(HTMLとJSON)を生成する
      3. 生成完了後に、JSONファイルをブラウザ側に渡し、ページを表示する
      4. 一度、静的ファイルが生成されると、サイトマップに登録され、以降は他のページ同様に静的ファイルを返却する
const Post = (props) => {
  const router = useRouter()
  // getStaticPathsで指定していないパスのデータが取得されるまで、Fallbackページが表示される
  if (router.isFallback) {
    return <div>Loading...</div>
  }
  // Render post...
}

export const getStaticPaths = async () => {
  return {
    paths: [
      { params: { productId: '1' } },
      { params: { productId: '2' } }
    ],
    fallback: true
  }
}

export const getStaticProps = async ({ params, preview, previewData }) => {
  // headless CMSからデータを取得する
  return {
    props: {}, // will be passed to the page component as props
    revalidate: 1
  }
}

getServerSideProps(For SSR)

公式ドキュメント:getServerSideProps

getServerSideProps は、SSRのときにサーバーサイドでのみ実行されるAPIである。getInitialProps とほぼ同義である。リクエストがきた際に、サーバーサイドでデータの取得を行い、プリレンダリングを行ったデータをクライアントサイドに送信する。

ただし、getInitialProps と比較して、next linkでクライアントサイドでルーティングを行った場合の処理が異なる。getInitialProps の場合は、サーバーサイドと同様に内部の処理がフロントサイドで実行されていた。しかしかしながら、getServerSideProps の場合は、next linkでルーティングした場合にもサーバーで実行されるように、クライアントサイドから APIリクエストをサーバーに送り、実行結果が含まれるJSONファイルをサーバーが返却してくれる。このJSONファイルを使って、クライアントサイドでレンダリングを行う。これらの処理は設定することなく、Next.js がバックグラウンドで自動でやってくれるというのだから、驚きだ。

export const getServerSideProps = async (context) => {
  // APIなどでデータを取得する
  return {
    props: {}, // will be passed to the page component as props
  }
}

まとめ

Next.js のデータ取得のためのAPI に関して、整理をすることができた。API やメソッドはいつ、どこで使用すべきか、知っているか、知らないかで大きく実装方法などが異なるので、これからもしっかりとキャッチアップしていきたいと思えた。また、Next.js は、プリレンダリング時に、HTML と JSON ファイルを生成して、自動で上手く処理をしているようなのですごいと思えた。

それでは、ステキな開発ライフを。