🙄

SWRで爆死を避ける。firebase Cloud FirestoreとNext.js。

に公開
6

Discussion

uttkuttk

今回の教訓は、SWRとfirestoreの相性はあまりよくない。

これはちょっと言いすぎなんじゃないかなぁー🤔と思っています。

再検証機能によってfirestoreの使用量が多くなったのは、実装の問題であってSWRとfirestoreとの相性の問題では無いと思いますし、SWRは非同期処理の状態管理・キャッシュの管理・エラーハンドリングなどをやってくれているので、仮に再検証機能を無効にしたとしても使う価値は十分あると思います。

なので、「 SWRとfirestoreの相性はあまりよくない。」ではなく、「 SWRを使う時は再検証機能に気をつけよう! 」とか 「 ドキュメントはちゃんと読もう! 」などの表現が適切な気がします( タブン )。

ここからは余談ですが、focusThrottleIntervalオプションで検証する期間( ポーリングフェッチする期間 )を指定することが出来ます。デフォルトでは 5000ms と、結構短めです。
なので、このオプションを適切に設定する事で、再検証機能をより有効に扱えるようになると思います。

バリデーションについては、個人的にzodがおすすめです。

https://github.com/colinhacks/zod/tree/v3

バリデーションの実装から型を生成できるので、バリデーションと型の実装が一気にできます。
( Transformersはとても便利な機能の一つです✨ )

最後に、SWRの再検証機能は気をつけないといけないのは事実なので、こうして記事にしてくれた事はとても参考になるモノでした! 私のプロダクトでも firestore( firebase ) + SWR を使っているので、実装を今一度見直してみたいと思います💪

mast1ffmast1ff

ご返信ありがとうございます!

これはちょっと言いすぎなんじゃないかなぁー🤔と思っています。
再検証機能によってfirestoreの使用量が多くなったのは、実装の問題であってSWRとfirestoreとの相性の問題では無いと思いますし、SWRは非同期処理の状態管理・キャッシュの管理・エラーハンドリングなどをやってくれているので、仮に再検証機能を無効にしたとしても使う価値は十分あると思います。
なので、「 SWRとfirestoreの相性はあまりよくない。」ではなく、「 SWRを使う時は再検証機能に気をつけよう! 」とか 「 ドキュメントはちゃんと読もう! 」などの表現が適切な気がします( タブン )。

少し煽りが過ぎましたね・・・。
実際には実装の問題ですし私の失敗談なので、SWRに転嫁する書き方はご指摘の通り修正をさせていただきました。

その上でこれは反論ではなく個人的な見解なのですが、上記のようなfirestore自体の取得処理の冗長性から、Reactでの使用ではcontextやreduxなどでのストアで管理する実装が周りにも多く、firestore自体にsnapshot機能があるために、データの再検証自体は本体に十分な機能が備わっていると思っています。そこまで実装した上でSWRを使おうと思い立ったのはAPIサーバと同じ感覚で本当に脳死状態だったわけですが・・・😅

Next.jsに限って言えば、セキュリティルールでクライアントからのリクエストをすべて拒否した上で、
おっしゃったように

ここからは余談ですが、focusThrottleIntervalオプションで検証する期間( ポーリングフェッチする期間 )を指定することが出来ます。デフォルトでは 5000ms と、結構短めです。

のようなオプションやmutationと一緒にAPI RouteでREST化して使う実装が一番手数も少なくて済みそうだな、とは思っています。

バリデーションについては、個人的にzodがおすすめです。
バリデーションの実装から型を生成できるので、バリデーションと型の実装が一気にできます。
( Transformersはとても便利な機能の一つです✨ )

ご提案ありがとうございます!さらっと目を通させていただきました。触ったことのないライブラリでしたので、ご提案嬉しいです!

fierstoreしかりのクラウドDBや関数でサーバーレスが進む中、エラハン不慣れなデザイナやフロント周りの人へロジック組みましょう!なケースも個人的に増えてきているので、一層こんな単純なミスをしないよう気を引き締めなければならないですね😑

CatminusminusCatminusminus

SWRを使用することになり、そのRevalidationの挙動を調べるにあたり、本記事が参考になりました。ありがとうございます。
ですが、調査する中でいくつか気になる点がありまして、質問させていただければと存じます。

本記事では、

SWRは数秒に一度データの検証を行い、差分を検知することで変更をフロントエンドに反映させることが出来る機能を持っています。
そしてこの機能はデフォルトでONとなっています。

とありますが、これはデフォルトではOFFになっていませんでしょうか。

といいますのは、この機能はfocusThrottleIntervalオプションではなく、refreshIntervalの設定により有効化されるもののように思われます。そしてこちらはデフォルトでは無効化されています。

refreshInterval = 0: ポーリングの間隔(デフォルトでは無効) (詳細)

https://swr.vercel.app/ja/docs/options

またfocusThrottleIntervalはポーリングフェッチの間隔の設定値ではなく、仮にrevalidateOnFocusがtrueとなっていても、前回からfocusThrottleInterval経過していなければrevalidateしないようにする間隔ではないでしょうか。

これは、

focusThrottleInterval = 5000: この期間中に一度だけ再検証をします

(上と同じ公式ドキュメントにおける記述)

及びソースコード中でfocusThrottleIntervalが使われている部分

https://github.com/vercel/swr/blob/f10e744e78bca9679c104dab7d04c39fb0f06766/src/use-swr.ts#L465-L476

及び実際の動作を見て判断しました。

mast1ffmast1ff

ご指摘ありがとうございます。
そのとおりですね!
期間指定でのデータ再検証はrefreshIntervalを利用するのが正解です。
私の記述が間違っておりました。誤解を招いてしまい、大変申し訳ございませんでした。

該当部分を修正させていただきます。

Victor ManuelVictor Manuel

私の視点から見ると、FirebaseとNext.jsをどのように組み合わせても、自分の足を撃つようなものです。常にうまくいかず、推奨されません。Next.jsを使うなら、Node.jsや他のバックエンドを使うべきで、Firebaseとは併用しない方が良いでしょう。Firebaseを使うなら、それを最大限に活用すべきです。すべてをクライアントで行い、サーバーサイドでレンダリングが必要な部分だけサーバーで処理する場合を除いて、Nextは必ずしも必要ではありません。

mast1ffmast1ff

ご返信ありがとうございます。この記事は3年以上前のものであり、当時はNext.jsのApp RouterやReact Server Componentsなどの機能はありませんでした。加えてVercelなどのサーバーレスなホスティング環境から利用できる安価なデータベースの選択肢が少なかったため、Next.jsやNuxtなどのフロントエンドが出自のフルスタックフレームワークとFirestoreとを組み合わせて利用するケースの需要は多かったように思います。
当時のNext.jsでSSRを行う手段はgetServerSideProps以外存在しなかったため、UIに必要なデータの一部をクライアントで取得する場合はfetchを用いた実装や、Firestoreであればこの記事のようなSDKを使用した実装となります。現在であれば"use server"とサーバーアクションでしょうね。

今となっては、Next.jsを含むフレームワークや周辺技術も進歩し、データベースやホスティング環境にも安価な選択肢も増えたため、おっしゃる通り用途に合わせて様々な手段が取れるでしょう。