[Next.js]router.queryから初回のundefinedを消し去る方法

2021/09/20に公開2

Next.jsの初回queryのundefined現象

  • src/pages/[q].tsx
import { useRouter } from 'next/router'
import React from 'react'

const Page = () => {
  const router = useRouter()
  const q = router.query['q']
  console.log("q:",q)
  return <div>{q}</div>
}

export default Page

  • 実行結果

http://localhost:3000/query

console.logの結果

q: undefined
q: query

出力されたHTML

<div></div>

素直にプログラムを組むと、初回はundefinedになっており、SSR後のHTMLも空になっています。

一瞬で解決してみる

この現象の解決方法を検索すると、undefinedの時はいったんnullを戻したり、実処理をuseEffect後にするとかいう解決策が示されています。
実はもっと簡単に直すことが出来ます。

以下のファイルを設置してください。

  • src/pages/_app.tsx
import App from 'next/app'
App.getInitialProps = async () => ({ pageProps: {} })
export default App

以上です。

解決後の動作

console.logの結果

q: query

出力されたHTML

<div>query</div>

ということでundefinedは消え去り、SSRもきっちりqueryのデータを受け取った上で行われます。

何故解決するのか

getInitialPropsを入れると、Appコンポーネントのpropsにqueryが送られるようになります。
これが入っていない場合はクライアントでqueryを作り直すので、stateの入れ替えのワンクッションの結果undefinedになります。

デフォルトでqueryを渡さないのは何か事情があるのかもしれませんが、とにかくこれで解決です。

GitHubで編集を提案

Discussion

kenbu🏠PICK/CTOkenbu🏠PICK/CTO

_app.tsxにgetInitialProps()入れてしまうと、全てのページがSSRになってしまうのでよくないのでは?と思いました。
https://nextjs.org/docs/api-reference/data-fetching/get-initial-props

router.isReadyを使って制御した方が良いかと。

const router = useRouter();
router.isReady // return true if ready router

https://nextjs.org/docs/api-reference/next/router

空雲空雲

この内容は初回のundefinedを消す方法であって、良い悪いという話が出てくるのは意図がよく分かりません。
用途によってqueryを巻き込んでSSRされたくない場合があるのならもちろん組み方を考えるべきですが、あくまで用途の問題であって良い悪いという話ではありません。

なお、Next.jsはgetInitialProps()の有無に関わりなく、もともと全てのページがSSRされます。