5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

データ取得に役立つSWR

Last updated at Posted at 2021-08-08

SWRとは

Next.jsを提供しているVercel社が開発しているデータ取得用のReact Hooksライブラリです。命名はHTTPキャッシュ無効化戦略であるstale-while-revalidateに由来します。

SWRの特徴

  • Jamstack指向
  • 高速且つ軽量で再利用可能なデータ取得
  • リアクティブな動作の実現
  • 重複リクエストの排除
  • 複雑なロジックの単純化

使い方

import useSWR from 'swr';

const fetcher = (url: string): Promise<any> => fetch(url).then(res => res.json());

function Profile () {
  const { data, error } = useSWR('/api/user/123', fetcher);

  if (error) return <div>failed to load</div>;
  if (!data) return <div>loading...</div>;

  // データをレンダリングする
  return <div>hello {data.name}!</div>;
};

なんてことでしょう。シンプル過ぎてわからない。
これでは仕様がわかりづらいと思いますので、簡単に解説します。

引数

// 定型
const { data, error } = useSWR(key, fetcher, option);

// 実例
const { data, error } = useSWR('/api/user/123', fetcher, { refreshInterval: 3000, revalidateOnReconnect: true });
  • 第一引数
    • このリクエストのためのユニークなキー文字列(または関数、配列、null)
    • 主にリクエスト先のURLを指定する
  • 第二引数
    • fetcher(Fetch API等のデータ取得してPromiseを返却する関数)
    • GETメソッド且つFetch APIを利用出来る環境であれば、省略可能
  • 第三引数
    • useSWRのオプション

返り値

const { data, error, isValidating, mutate } = useSWR('/api/user/123', fetcher);
  • data
    • 取得したデータ、もしくはundefined(データ取得中、もしくはデータ取得できなかった場合)
  • error
    • データ取得時のエラー、もしくはundefined(データ取得中、もしくはエラー発生しなかった場合)
  • isValidating
    • ローディング中(リクエスト中)にtrueとなるboolean型の変数
    • 例えば、ローディング中に実行したい処理がある場合に利用すると便利です。
  • mutate
    • キャッシュされたデータを更新する関数
    • 例えば、useSWRで取得したデータが何らかの方法で更新された場合、そのままでは取得時のキャッシュは更新されません。もちろん再取得すれば更新されますが、mutateを使えば再取得を待たずしてキャッシュの内容を更新することができます。

ちなみにdata及びエラーはPromiseを解決した値が返却されます。
このように複数の返り値を持ちますが、不要な返り値を受け取ると無駄な再レンダリングが発生する可能性がありますので、必要な値だけを受け取るようにしましょう。

オプション

名称 効果 デフォルト値
suspense React Suspenseモードを有効にする boolean false
initialData データの初期値を設定します any undefined
revalidateOnMount コンポーネントがマウントした時に自動的に再検証する boolean initialData が設定されてない場合、true
revalidateOnFocus ウィンドウがフォーカスされた時に自動的に再検証する boolean true
revalidateOnReconnect ブラウザがネットワーク接続を回復すると自動的に再検証する(navigator.onLine経由) boolean true
refreshInterval ポーリングする時間間隔 number 0(無効)
refreshWhenHidden ウィンドウが非表示の場合にポーリングする(refreshIntervalが有効になっているときのみ) boolean false
refreshWhenOffline ブラウザがオフラインのときにポーリングする(navigator.onLineによって決定される) boolean false
shouldRetryOnError フェッチャーでエラーが発生したときに再試行する boolean false
dedupingInterval この期間内での同じキーのリクエストを重複として排除する number 2000
focusThrottleInterval この期間中に一度だけ再検証する number 5000
loadingTimeout onLoadingSlowイベントをトリガーするためのタイムアウト number 3000
errorRetryInterval エラー再試行の時間間隔 number 5000
errorRetryCount 最大エラー再試行回数 number exponential backoffアルゴリズムを使用してエラーの再試行を処理
onLoadingSlow(key, config) リクエストの読み込みに時間がかかりすぎる場合のコールバック関数 (key: string, config: SWROptions) => void undefined
onSuccess(data, key, config) リクエストが正常に終了したときのコールバック関数 (data: any, key: string, config: SWROptions) => void undefined
onError(err, key, config) リクエストがエラーを返したときのコールバック関数 (error: any, key: string, config: SWROptions) => void undefined
onErrorRetry(err, key, config, revalidate, revalidateOps) エラー時の再試行をするコールバック (error: any, key: string, config: SWROptions, revalidate: (options: RevalidateOptions) => Promise<boolean>, revalidateOptions:{ dedupe: boolean; retryCount: number; }) => void undefined
compare(a, b) 誤った再レンダリングを回避する返却データ更新時系列を検出するための比較関数 (a: any, b: any) => boolean dequalを使用
isPaused() 再検証を一時停止するかどうかを検出する関数 () => boolean () => false

※refreshWhenHiddenはrefreshIntervalが有効になっている場合に動作します。trueに設定する時は必ずrefreshIntervalを設定してください。
※isPausedがtrueを返す場合、再検証を停止して取得したデータとエラーを無視する

オプションのグローバル設定

上記のオプションをuseSWRを利用する度に記述するのは少し面倒です。useSWRを利用する上で共通して設定したいオプションは以下のようにSWRConfigに記述することで設定できます。

import useSWR, { SWRConfig } from 'swr'

function Dashboard () {
  const { data: events } = useSWR('/api/events')
  const { data: projects } = useSWR('/api/projects')
  const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // SWRConfigで設定したオプションをオーバーライド
  // ...
}

function App () {
  return (
    <SWRConfig 
      value={{
        refreshInterval: 3000,
        fetcher: (resource, init) => fetch(resource, init).then(res => res.json())
      }}
    >
      <Dashboard />
    </SWRConfig>
  )
}

最後に

複雑な非同期処理を単純にしてくれるSWRくん
Reactベースの開発を行っている場合は学習コストが低いと思いますので、一度採用を検討してみてはいかがでしょうか。

参考URL

SWR データ取得のためのReact Hooksライブラリ
SWRはHTTPキャッシュ無効化戦略の夢を見るのか? - Zenn

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?