🦔

Next.js v12.2 オンデマンド機能をわかりやすく解説する

2023/01/20に公開約2,900字

概要

Next.jsの便利な機能としてオンデマンド機能があります。
今回はその機能について、例を交えながら解説していきます。

環境

Next.js v12.2

オンデマンド機能 is 何

オンデマンド単体の意味は「要求に応じて」です。
つまり、要求に応じてコンテンツを更新する機能になります。

現在時刻を表示させるデモ

ここでは現在の時刻を表示させるデモを使用します。

getStaticPropsを使う

新たにNext.js.プロジェクトを作成し、index.jsx のコードを書き換えます。

pages/index.tsx
export const getStaticProps = () => {
  const currentTime = new Date().toLocaleString()

  return {
    props: {
      currentTime
    }
  }
}

export default function Home({ currentTime }) {
  return (
    <>
      <Head>
        <title>Test On Demand</title>
      </Head>
      <section>
        <h1>Current Time is...</h1>
        <p>{ currentTime }</p>
      </section>
    </>
  )
}

この状態でビルドnpm run buildを行い、npm run startで表示を確認してみましょう。

何回かリロードしても時刻は変わりませんね。これは静的サイトとして書き出されているので動的に変更することがないからです。

そこで解消案として、ISRがあります。

ISR

ISR(Incremental Static Regeneration)については詳しく言及しませんが、簡単に言うとページキャッシュを作成し、一定時間のち新たにキャッシュを作り新たなデータを返す機能になります。

pages/index.tsx
export const getStaticProps = () => {
  const currentTime = new Date().toLocaleString()

  return {
    props: {
      currentTime
    },
    revalidate: 60 // revalidate time
  }
}

これで定期的(今回は60秒毎)にキャッシュが作り直され、ページに現在時刻が反映されました。ですが、ここでは以下が問題視されています。

60秒経たないと更新されない

とはいえ、10秒でいいじゃないと思われますが、そうなってくるとISRのメリットが生かせない状態になります。
この部分を解決してくれるのがオンデマンドISRになります。

オンデマンドISR

このオンデマンドISRは、任意のタイミング(コンテンツ更新など)で再検証を実施することができます。

pages/index.tsx
export default function Home({ currentTime }) {
  const [message, setMessage] = useState('')
  const revalidate = async () => {
    const res = await fetch('/api/revalidate')
    const data = await res.json()
    setMessage(data.message)
  }

  return (
    <>
      <Head>
        <title>Test On Demand</title>
      </Head>
      <section>
        { message && <p>{message}</p> }
        <h1>Current Time is...</h1>
        <p>{ currentTime }</p>
        <button type="button" onClick={revalidate}>再検証</button>
      </section>
    </>
  )
}
pages/api/revalidate.ts
const handleRevalidate = async (_, res) => {
  try {
    await res.revalidate('/')
    return res.json({ message: '再検証完了' })
  } catch (err) {
    return res.status(500).json({ message: '再検証に失敗しました' })
  }
}

export default handleRevalidate

ボタンを押した際にオンデマンド機能が作動し、リロードした時にデータが更新されていることがわかります。

ここで注目するのが、res.revalidate('/') です。
ここで再検証しているのですが、引数の中は対象になるパスを指定します。

オンデマンド機能のメリットとデメリット

メリットはなんと言っても任意のタイミングでデータキャッシュを新しく更新できるところです。
デメリットはどのパスを任意更新するか設計を立てる必要があるということです。

頻回にコンテンツ更新するならばオンデマンド機能が有用でしょうか。逆に更新頻度が少ない場合はISRを使用したほうが負荷は少ないでしょう。

最後に

オンデマンド機能は、キャッシュ戦略としての問題に一石を投じる素晴らしい機能だと思います。

参考記事

Next.jsのISRで動的コンテンツをキャッシュするときの戦略 https://zenn.dev/catnose99/articles/8bed46fb271e44
On-Demand Incremental Static Regeneration (Stable) https://nextjs.org/blog/next-12-2
Next.js 12.1の新機能オンデマンド ISRでページを手動再検証させてみた https://dev.classmethod.jp/articles/next-js-12-1/

Discussion

ログインするとコメントできます