Next.js でクエリ文字列が使いたいときは getServerSideProps を使う

こんにちは kimizuy です。

今回はタイトルのとおりなんですが、Next.js でクエリ文字列を使いたいときは getServerSideProps を使おう、というテーマで記事をご紹介します。

クエリ文字列というのは URL の末尾に付け足す「?」以降の文字列を指します。

https://example.com/?foo=fuga

上記の場合は「foo」がパラメータで「fuga」が値ですね。

tldr

さっそく、getServerSideProps とクエリ文字列を組み合わせたページコンポーネントのコード例を示します。この例では page というクエリの値をそのまま表示しています。

例えば http://localhost:3000/slug?page=42 の場合は以下のような表示になります。

Slug is slug.
Page is 42.
// pages/[slug].tsx

import { GetServerSidePropsContext, InferGetServerSidePropsType } from 'next'

type Props = InferGetServerSidePropsType<typeof getServerSideProps>

const Page = ({ slug, page }: Props) => {
  return (
    <div>
      <p>Slug is {slug}.</p>
      {page && <p>Page is {page}.</p>}
    </div>
  )
}

export const getServerSideProps = async ({
  params,
  query,
}: GetServerSidePropsContext<{ slug: string }>) => {
  const slug = params?.slug
  const page = query.page

  return {
    props: { slug, page },
  }
}

export default Page

getStaticProps ではクエリ文字列を取得できない

Next.js はビルド時にページを事前生成する getStaticProps があり、リクエストを受けてからサーバーサイドでページ生成する getServerSideProps よりもパフォーマンス面で優位です。

しかし getStaticProps はクエリ文字列を取得できる仕様ではないため、クエリ文字列を含むような多様な URL に対して柔軟さに欠けます。これは上記のとおり、あらゆるパターンの URL に対してビルド時に事前生成することは現実的でないことが考えられます(fallback: "blocking" のように SSR っぽい動きもできるので無理ではない気もしていますが)。

export type GetStaticPropsContext<
  Q extends ParsedUrlQuery = ParsedUrlQuery,
  D extends PreviewData = PreviewData
> = {
  params?: Q
  preview?: boolean
  previewData?: D
  locale?: string
  locales?: string[]
  defaultLocale?: string
}

getStaticProps でも /search?title=vercel&page=1/search/vercel/1 のようにして無理矢理扱うこともできますが、パスの仕分けには正規表現などが必要になり危うい設計だと感じます。

参考: Make getStaticProps support URL query string

補足

併用不可

同じページコンポーネント内では getStaticProps (& getStaticPaths) と getServerSideProps は併用できません。

getInitialProps は?

getServerSidePropsgetStaticProps の登場以来、Next.js は基本的にこのどちらかを使うことを推奨しています。

理由については「SSRはおまいらには早すぎた 〜Next.jsのgetServerSidePropsの登場が何を意味するか〜」が詳しいです。

が、端的に言うと getInitialProps はクライアントとサーバサイドの両方で動くためコードが複雑化しやすく、また認証が伴う個人ページなどは SSR ではなくクライアントで最新のデータを取得するほうが安全なためクライアントとサーバサイドで明確に責務を分ける必要が出てきたからです。

おわりに

今回は Next.js でクエリ文字列を扱う方法についてご紹介しました。

以上、お読みいただきありがとうございました。

この機会に、オンラインで気軽に面談してみませんか?

現在弊社では一緒にお仕事をしてくださるエンジニアさんやデザイナーさんを積極募集しています。まずはカジュアルな面談で、お互いに大事にしていることをお話できたらうれしいです。詳しい応募要項は以下からチェックしてください。

パートナー契約へのお問い合わせもお仕事へのお問い合わせも、どちらもいつでも大歓迎です。まずはオンラインでのリモート面談からはじめましょう。ぜひお気軽にお問い合わせください!

お問い合わせしてみる!


投稿者 Yamasaki Kimizu

React, Redux, TypeScript プロジェクトでフロントエンド領域を担当。個人でも Next.js アプリの開発をしています。日課はRSSで取得した技術記事を読むこと、最近の関心は Core Web Vitals です。将来はでかい犬が飼いたいです。