Next.js の SG, ISR (with Apollo) の仕組みを作りながら学んでみた（getStaticProps と getStaticPaths の理解と実装）1/5

## はじめに

Next.js の SG + ISR (with Apollo) の仕組みを作りながら学んでみたシリーズ

このシリーズでは、Hasuraで用意した仮想のユーザーデータを外部APIとして取得しながら、

ユーザーの一覧ページと詳細ページを作りながら、SGと ISRを学ぶ記事です。

https://qiita.com/ryosuketter/items/ab7d4c8bfb19185f7b1e

今回は、getStaticProps と getStaticPaths の理解と必要な実装について書きます。

## 目次

- 実装
    - 一覧ページ
        - [getStaticProps](https://qiita.com/ryosuketter/items/442db08856093e6cfeea) 👈 今回はコレ
        - [必要なモジュールのimport](https://qiita.com/ryosuketter/items/8c4820c06a441c717180)
        - [interface作成](https://qiita.com/ryosuketter/items/8c4820c06a441c717180)
        - [コンポーネント作成](https://qiita.com/ryosuketter/items/8c4820c06a441c717180)
    - 詳細ページ
        - [getStaticProps と getStaticPaths](https://qiita.com/ryosuketter/items/799d3330ab7cda37145c)
        - [必要なモジュールのimport](https://qiita.com/ryosuketter/items/cb2507559c6c71bf9f17)
        - [interface作成](https://qiita.com/ryosuketter/items/cb2507559c6c71bf9f17)
        - [コンポーネント作成](https://qiita.com/ryosuketter/items/cb2507559c6c71bf9f17)
- 検証
    - [作ったものをブラウザで見ながらSGとISRの仕組みをざっくり理解する](https://qiita.com/ryosuketter/items/af45c292249ea7a88d9d)

## SGという用語に関して

SSGと言ったり、SGと言ったりするかもしれませんが、SSGはかつての呼び方なのでSG（Static Generate）に統一して書こうと思います。

仕組みは同じものだと思ってください。

## 最終的なゴール

以下のような構成のアプリを作ることです。

![スクリーンショット 2021-10-18 17.27.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/14191/e8a9a2e1-2723-4fec-77ef-be3b9eefdd81.png)

### 目的

- 仕事で使っている技術のキャッチアップと復習
- 使う可能性がある技術の理解度向上

## pre-renderingについて

（意味を先に言うと、**事前にHTMLを生成すること**です。）

Next.jsにおいて、重要な概念に`pre-rendering`があります。

Next.jsは、デフォルトで全てのページで`pre-rendering`しています。

ちなみに、React単体には`pre-rendering`の機能はありません。

なので、通常のReactで構築されたページよりもSEO的なメリットもあるかもです。

### hydration

`pre-rendering`されると、HTMLは必要最低限のJSコードとともに生成されます。

ブラウザによるロード時にこのJSが実行され、ページが完全にインタラクティブなものになります。

これをハイドレーション(hydration)と呼びます。

### pre-renderingには二種類ある

`pre-rendering`には二種類あります。

- 外部データを必要としないpre-rendering
- 外部データを必要とするpre-rendering
    - 外部API（本記事ならHasuraなど）から取得してきたデータを一覧表示するページを作成したいとき
        - そんなときに使用するのがgetStaticProps

https://nextjs.org/learn/basics/data-fetching/pre-rendering

## getStaticPropsとgetStaticPathsの要点

- getStaticProps
    - ビルド時に静的なファイルを生成し、ページコンポーネントで使用する値を用意する
    - Next.jsで`pre-rendering`を行う際に、外部データが必要な時に使用する関数
        - `pre-rendering` : webページにアクセスする前にページを表示するのに必要なHTMLを構成しておく」という意味です
- getStaticPaths
    - ビルド時にレンダリングする必要のあるパスのリストを生成する

これらの関数はクライアント側での実行でなく、必ずサーバーサイドで実行されます。

## getStaticProps

`getStaticProps`と`getStaticPaths`はSG用のAPIで、静的なデータを事前（ビルド時）に生成してくれます。

クライアント側で実行されず、サーバーサイドで実行されますが、アクセスの度にSSRはしません。

ビルド時にデータを取得し静的なファイルを事前に生成します。

なので、再ビルドしない限りいつアクセスしても同じ結果です。

## getStaticPaths

のちのち説明するので、getStaticPathsの概要も把握しておきます。

`getStaticPaths`は`Dynamic Routes`利用時にも静的なファイルを生成するためのAPIです。

こちらも、`getStaticProps`と同様に、再ビルドしない限り、いつアクセスしても結果は同じです。

### Dynamic Routesとは

Next.jsでは、`pages/`配下でファイル名にブラケット（`[]`）を使用することで自動的にダイナミックルーティングされる仕組みのことです。

ダイナミックルート用のファイルでは、`getStaticPaths`と`getStaticProps`の関数が必要です。

https://nextjs.org/docs/routing/dynamic-routes

このシリーズ内の今後の記事で実装していきます。

## 実装

本記事で必要な部分だけ実装しました。

```tsx
// GetStaticProps 用の型
import { GetStaticProps } from 'next'
import { initializeApollo } from '../lib/apolloClient'
// GetStaticProps で、ユーザーのリストを取得するのでqueriesからimport
import { GET_USERS } from '../queries/queries'
// GET_USERSの型
import { GetUsersQuery } from '../types/generated/graphql'

// ビルド時にサーバーサイドで実行される
export const getStaticProps: GetStaticProps = async () => {
  // サーバーサイドでinitializeApolloを実行し、apolloClientを生成
  const apolloClient = initializeApollo()
  // 生成したapolloClientで、クエリ（GET_USERS）をHasuraに投げる
  // await で同期化して、{ data } で受け取っている
  const { data } = await apolloClient.query<GetUsersQuery>({
    query: GET_USERS,
  })
  // usersという名前にして、user情報を返している
  // 
  return {
    props: { users: data.users },
    revalidate: 1,
  }
}
```

### revalidate

関数`getStaticProps`から`return`するオブジェクトの中で、`revalidate`というキー名に対して数値を指定します。

この単位は秒数です。なので、ここでは 1 ですから 1 秒という時間を指定しています。

`revalidate`を指定すると、自動的にISRが有効化されます。

`revalidate`をたとえば 1秒に指定すると、`getStaticProps`を使ってSGが行われる各ページについて、1秒間はこれまでと同様に静的な HTML（のキャッシュ）をサーブします。

しかし、1秒経過した後に初めてユーザーからリクエストがあったタイミングで、そのリクエストに対してはすでに構築済みのHTML（のキャッシュ）を返しつつ、バックグラウンドでデータの再取得および再レンダリングを行いページを再生成し、次のリクエストに対しては再生成したページのキャッシュを返します。

これにより、時間の経過に応じて内容が変化する部分でも、アプリ全体を再ビルドすることなくその変化を反映させることができます。

今は秒数を 1秒として説明しましたが、データの性質に応じてこの秒数を調整できます。

また、`revalidate`で指定した時間の経過後にリクエストが行われ、ページを再生成している間は、再生成する前の（つまり、生成済みの）HTML（のキャッシュ）を返すので、ページを再生成するタイミングで応答が遅くなるというようなことはありません。

またデータの再取得に失敗するなどしてページの再生成ができなかった場合は、過去にサーブしていたキャッシュがその後もサーブされます。

## まとめ

今回は、getStaticProps と getStaticPaths の理解と必要な実装について書きました。

## 参考

https://nextjs.org/blog/next-9-3

## 次回

https://qiita.com/ryosuketter/items/8c4820c06a441c717180

## アウトプット100本ノック実施中

https://qiita.com/ryosuketter/items/713474dbd009870e4103