Next.jsのインクリメンタル静的再生(ISR)でのSWRReactフックの使用
公開: 2022-03-10Next.jsでインクリメンタル静的再生(ISR)を使用したことがある場合は、古いデータをクライアントに送信していることに気付いたかもしれません。 これは、サーバー上のページを再検証するときに発生します。 一部のWebサイトではこれが機能しますが、他のWebサイト(@lachlanjcによって構築されたサイトであるHack ClubのScrapbookなど)では、ユーザーはデータが最新の状態に保たれることを期待しています。
頭に浮かぶ最初の解決策は、単にサーバー側でページをレンダリングし、クライアントに常に最新のデータが送信されるようにすることです。 ただし、レンダリングする前に大量のデータをフェッチすると、最初のページの読み込みが遅くなる可能性があります。 Scrapbookで使用された解決策は、ReactフックのSWRライブラリを使用して、クライアント側のデータフェッチでサーバーからキャッシュされたページを更新することでした。 このアプローチにより、ユーザーは引き続き優れたエクスペリエンスを享受でき、サイトは高速であり、データは最新の状態に保たれます。
SWRに会う
SWRはVercelによって構築されたReactHooksライブラリであり、その名前はstale-while-revalidateという用語に由来しています。 名前が示すように、クライアント側のSWRを介して最新のデータがフェッチ(再検証)されている間、クライアントには古い/古いデータが提供されます。 SWRはデータを一度だけ再検証するだけではありませんが、タブがフォーカスを取り戻したとき、クライアントがインターネットに再接続したとき、またはプログラムでデータを再検証するようにSWRを構成できます。
ISRおよびNext.jsのAPIルートと組み合わせると、SWRを使用してレスポンシブなユーザーエクスペリエンスを作成できます。 クライアントは最初にキャッシュされた静的に生成されたページ( getStaticProps()
で生成された)を提供され、バックグラウンドでサーバーはそのページを再検証するプロセスも開始します(詳細はこちらをご覧ください)。 このプロセスはクライアントにとっては速く感じられ、データのセットを見ることができるようになりましたが、少し古くなっている可能性があります。 ページが読み込まれると、 getStaticProps()
で生成されたものと同じデータを返すユーザーのNext.jsAPIルートに対してフェッチリクエストが行われます。 このリクエストが完了すると(成功したと仮定して)、SWRはこの新しいデータでページを更新します。
ここで、Scrapbookと、これがページに古いデータがあるという問題の解決にどのように役立ったかを振り返ってみましょう。 明らかなことは、クライアントが更新されたバージョンを取得することです。 しかし、もっと興味深いのは、私たちの側の速度への影響です。 Lighthouseを介して速度を測定すると、サイトのISR + SWRバリアントで1.5秒、サーバー側レンダリングバリアントで5.8秒の速度インデックスが得られます(さらに、サーバーの初期応答時間に関する警告)。 これは、2つの間のかなり明確な対照です(そして、ページをロードするときにも顕著でした)。 ただし、トレードオフもあります。サーバー側のレンダリングページでは、新しいデータが入力されて数秒後にユーザーがサイトのレイアウトを変更できませんでした。Scrapbookはこの更新を適切に処理すると思いますが、次の場合に重要な考慮事項です。ユーザーエクスペリエンスの設計。
SWRを使用する場所(および使用しない場所)
SWRはさまざまな場所に配置できます。ここでは、SWRが最適なサイトカテゴリをいくつか示します。
- 迅速な更新が必要なライブデータのあるサイト。
このようなサイトの例としては、スポーツスコアサイトやフライト追跡などがあります。 これらのサイトを構築するときは、間隔を低く設定して(1〜5秒)間隔で再検証オプションを使用することを検討します。 - リアルタイムで更新される更新または投稿のフィードスタイルを持つサイト。
この典型的な例は、選挙などのイベントのライブブログがあるニュースサイトです。 別の例は、前述のスクラップブックでもあります。 この場合、データ使用量を節約し、不要なAPI呼び出しを防ぐために、間隔の再検証オプションを使用することもできますが、間隔の設定を高くします(30〜60秒)。 - より受動的なデータ更新を備えたサイトで、人々はバックグラウンドで多くのことを開いたままにします。
これらのサイトの例としては、天気のページや2020年代のCOVID-19の症例番号のページがあります。 これらのページはそれほど頻繁には更新されないため、前の2つの例を定期的に再検証する必要はありません。 ただし、それでもデータを更新するためのユーザーエクスペリエンスは向上します。 このような場合、タブがフォーカスを取り戻し、クライアントがインターネットに再接続した日付を再検証することをお勧めします。つまり、COVIDの症例がわずかに増加しただけであることを期待して、人が心配そうにタップに戻った場合です。そのデータをすばやく取得します。 - ユーザーが操作できる小さなデータを含むサイト。
Youtubeの[購読]ボタンを考えてみてください。[購読]をクリックすると、カウントが変化するのを確認し、違いを生み出したように感じます。 このような場合、SWRを使用してプログラムでデータを再検証し、新しいカウントをフェッチして、表示された量を更新できます。
注意すべき点の1つは、これらはすべてISRの有無にかかわらず適用できるということです。
もちろん、SWRを使用したくない場所やISRなしでSWRを使用したくない場所もあります。 SWRは、データが変更されていないか、ほとんど変更されない場合はあまり使用されません。代わりに、ネットワークリクエストを詰まらせ、モバイルユーザーのデータを使い果たす可能性があります。 SWRは認証が必要なページを処理できますが、このような場合は、増分静的再生成ではなく、サーバー側レンダリングを使用することをお勧めします。
Next.jsとインクリメンタル静的再生でのSWRの使用
これで、この戦略の理論を探求しました。それをどのように実践するかを探りましょう。 このために、政府が提供するこのAPIを使用して、シンガポール(私が住んでいる場所です!)で利用できるタクシーの数を示すWebサイトを構築します。
プロジェクト構造
私たちのプロジェクトは、3つのファイルを持つことで機能します。
-
lib/helpers.js
-
pages/index.js
(フロントエンドファイル) -
pages/api/index.js
(APIファイル)
ヘルパーファイルは、外部APIからデータをフェッチする関数( getTaxiData
)をエクスポートし、使用に適した形式で返します。 APIファイルはその関数をインポートし、デフォルトのエクスポートを、 getTaxiData
関数を呼び出して返すハンドラー関数に設定します。これは、GETリクエストを/api
に送信するとデータが返されることを意味します。
SWRがクライアント側のデータフェッチを実行するには、この機能が必要です。 最後に、フロントエンドファイルでgetStaticProps
をインポートし、 getTaxiData
で使用します。そのデータは、Reactページをレンダリングするフロントエンドファイルのデフォルトのエクスポート関数に渡されます。 これはすべて、コードの重複を防ぎ、データの一貫性を確保するために行います。 なんと一口です。今からプログラミングを始めましょう。
ヘルパーファイル
まず、 lib/helpers.js
にgetTaxiData
関数を作成します。
export async function getTaxiData(){ let data = await fetch("https://api.data.gov.sg/v1/transport/taxi-availability").then(r => r.json()) return {taxis: data.features.properties[0].taxi_count, updatedAt: data.features.properties[0].timestamp} }
APIファイル
次に、 api/index.js
でハンドラー関数を作成し、 getTaxiData
関数をインポートします。
import { getTaxiData } from '../../lib/helpers' export default async function handler(req, res){ res.status(200).json(await getTaxiData()) }
前述のプロジェクト構造以外に、SWRやISRに固有のものはありません。 そのようなものは今index.js
で始まります!
フロントエンドファイル
最初に実行したいのは、 getStaticProps
関数を作成することです。 この関数は、 getTaxiData
関数をインポートして使用し、追加の構成でデータを返します。
export async function getStaticProps(){ const { getTaxiData } = require("../lib/helpers") return { props: (await getTaxiData()), revalidate: 1 } }
返されたオブジェクトの再検証キーに焦点を当てたいと思います。 このキーは、実質的にインクリメンタル静的再生を可能にします。 静的ページを1秒ごとに再生成することが利用可能なオプションであり、クライアントがページにアクセスすると、そのオプションがバックグラウンドでトリガーされることをホストに通知します。 インクリメンタルスタティックリジェネレーション(ISR)の詳細については、こちらをご覧ください。
SWRを使用する時が来ました! 最初にインポートしましょう:
import useSWR from 'swr'
React-rendering関数でSWRを使用するので、その関数を作成しましょう。
export default function App(props){ }
getStaticProps
から小道具を受け取っています。 これで、SWRを設定する準備が整いました。
const fetcher = (...args) => fetch(...args).then(res => res.json()) const { data } = useSWR("/api", fetcher, {fallbackData: props, refreshInterval: 30000})
これを分解しましょう。 まず、フェッチャーを定義します。 これは、SWRが引数として必要とするため、フレームワークなどが異なるとセットアップが異なる可能性がある場合に、データをフェッチする方法を知ることができます。 この場合、SWRのドキュメントページで提供されている機能を使用しています。 次に、 useSWR
フックを呼び出します。引数は、データをフェッチするパス、フェッチャー関数、オプションオブジェクトの3つです。
そのoptions
オブジェクトでは、2つのことを指定しました。
- フォールバックデータ。
- SWRがデータを再検証する間隔。
フォールバックデータオプションは、 getStaticProps
からフェッチされたデータを提供する場所であり、データが最初から表示されるようにします。 最後に、オブジェクトの破棄を使用して、フックからデータを抽出します。
最後に、非常に基本的なJSXを使用してそのデータをレンダリングします。
return <div>As of {data.updatedAt}, there are {data.taxis} taxis available in Singapore!</div>
そして、私たちはそれをしました! ここに、インクリメンタル静的再生でSWRを使用する非常に基本的な例があります。 (この例のソースはここにあります。)
ISRで古いデータに遭遇したことがある場合は、誰に電話するかを知っています:SWR。
SmashingMagの詳細
- SWRReactHooksライブラリ
- SWRの紹介:リモートデータフェッチ用のReactフック、Ibrahima Ndaw
- ISR vs DPR:ビッグワード、簡単な説明、キャシディウィリアムズ
- Next.jsのグローバルvs.ローカルスタイリング、Alexander Dubovoj
- Next.jsのクライアント側ルーティング、Adebiyi Adedotun Lukman