next.jsのISRを使おうとして「なんか全然うまく行かない」ってなってたのがやっと理解出来たのでメモ
とりあえず見様見真似でISRはrevalidateとfallbackつければ良いんだな?とやってみたところ、どうもpropsが空Objectになってしまうようで悩んでいた。
例えば下記のような場合、エラーが起きる
// pages/greeting/[name].jsconstPage=(props)=>{// ↓ここでエラーreturn<div>Hello{props.name.toUpperCase()}</div>}exportconstgetStaticProps=async(req)=>{return{props:{name: req.params.name},revalidate:100}}exportconstgetStaticPaths=async(req)=>{return{paths:[],fallback:true}}exportdefaultPageTypeError: Cannot read property 'toUpperCase' of undefined 9 | // } 10 | > 11 | return <div>Hello {props.name.toUpperCase()}</div> | ^ 12 | }ここからよくよく調べたりドキュメントを読んだりしているとどうやらこれだけでは駄目らしいということがわかってきた。
まずfallback: trueの挙動として文字通り「fallback向けページ」を生成する。
fallbackページというのがはっきりしなかったが、これが「propsが空Object状態のページ」ということらしい。
このあとgetStaticPropsを呼び出し、そのJSONを当てはめた状態で再レンダリングするようだ。
TypeScriptで表せば、こういう違いになるだろう
// 通常のSSRの場合constPage:FC<{ foo:string, baz:string}>//`fallback:true`にした場合constPage:FC<{ foo:string, baz:string}|{}>ここから解決策を見ていく
これは簡素。fallback: "blocking"にすればよい。
exportconstgetStaticPaths:GetStaticPaths=async(req)=>{return{paths:[],fallback:"blocking"}}必ず先にビルドが走るので、propsが入っている状態になる
fallback: trueにしたままrouter.isFallbackの判定を入れるfallback: trueでのパフォーマンスを維持したいなら、下記のようにrouter.isFallbackを利用する。
import{ useRouter}from"next/router"constPage=(props)=>{const router=useRouter()if(router.isFallback){return<div>Loading...</div>}return<div>Hello{props.name.toUpperCase()}</div>}こうするとまずisFallback=trueの状態で空オブジェクトになり、その後getStaticPropsを取得する処理が走る。
next devではISRの検証は出来ないIn development (next dev), getStaticProps will be called on every request.
とのことで、devモードでは毎回getStaticPropsが呼び出される模様
バッジを受け取った著者にはZennから現金やAmazonギフトカードが還元されます。
