zeit製のswrがすごい


react hooksの登場とある程度の枯れ具合を見せてきて、益々利用する機会が増えているReact。
最近はreduxを採用する/しないで議論が白熱することが多くなってきていますが、今回はreduxを採用せずとも、ある程度のアプリケーションなら作れる選択肢の一つを紹介させていただきます。

初投稿なので、読みづらかったらスンマセン。

zeit製のライブラリ swr

今回の主役はこのswr。
reactのSSRフレームワークであるnextjsやPaaSのNowなどのを開発・運用しているzeitから最近登場したライブラリです。

このライブラリのREADMEの頭には、以下のように紹介されています。
SWR is a React Hooks library for remote data fetching.

そう、つまり、data fetchをhooksベースで記述するためのライブラリです。

どんな機能があるの?

  • 一度取得したデータをkey valueの形でキャッシュする(コードを読んだ感じ、react contextを利用しているようです。
  • 画面にフォーカスしたタイミングで、自動でdataを再fetchする
  • retry処理が組み込まれている(exponential backoffなどの高度なものでは無いです
  • pollingベースでデータを再fetchする
  • mutationでデータ更新時にキャッシュも更新する
  • pagination機能(これは正直、そんなに使わない気もする

何が嬉しいの?

キャッシュです。キャッシュ戦略が組み込まれているのです。

例えば、SPAにおいて以下のようなUXを提供したい時に、reduxを採用していないと辛かった経験は無いですか?

1. 一回のsessionの間で、2回以上同じページに遷移する可能性がある(回遊)
2. 2回目以降は、新たにデータを取得できるまで、前回表示したものを表示させたい
3. しかしmountのタイミングでcomponentのstateが初期化されてしまうので、訪れるたびに通信完了後にデータが描画される

このような場合に、reduxを採用すれば、シングルトンなオブジェクトを常に参照することによって

前回取得したデータを最初に表示 → 新しいデータが取得完了したらstoreを更新

となり、例のような問題を解決できます。

しかしreduxは導入コストが高く、アプリケーションを過度に巨大化させがちだと考えています。
世のアプリケーションの50%くらいはデータのCRUDするだけの機能しか無いと思いますし、そのためだけに採用するのは開発効率を考えても良くはないと考えています。(もちろんreduxはとても信頼できますし、ある程度のアーキテクチャが決まっているのでテスタビリティやアプリケーションの品質が保証できるという気持ちはあります。決してdisっているわけじゃないッス

swrはこれを解決できます。

そもそもデータ取得を実装する上で必要な要件ってなんだっけ?

基本的なことを振り返ります。
data fetchにおいて、アプリケーションとしては以下の3状態が設計されるべきです。

1. データ取得中 ... loading
2. データの取得完了 ... done
3. エラー発生 ... error

細かく言えば初期のmountのタイミングもありますが、doneと同じ扱いで良いのでここでは除きます。

swrはこの要件をしっかり満たしています。

使い心地は?

簡単な使用例を以下に載せました。



import useSWR from 'swr'

interface User {
   id: string
   name: string
}

// Promiseを返す関数であれば良い
const fetchUser: (id:string) => Promise<User> = .....

const Page = () => {

  // URLから取得するとか
  const id = ....
  const { data, error } = useSWR<User,Error>(`/users/${id}`, () => fetchUser(id))

  if (error) return <div>{error.message}</div>

  return (
     <div>
        {error && <div>{error.message}</div>}
        {!data && <div>loading.....</div>}
        {data && <div>こんにちわ{data.name}さん</div>}
     </div>
  )

}

自然な使い心地で良いですよね。
swr自体がtypescriptで実装されていることもあり、型もしっかり付いてきます。

現実的な使い方としてはuseSWRをwrapしたcustom hooksを実装して、使うことになりそうですね。

解決できたこととメリット

swrを使った場合、先ほどの例を元に遷移の様子をあげてみると以下になります。

# ユーザーが初めてページに訪れた場合
    1.キャッシュに存在しないので、dataはundefになる。
    2.取得完了したら、dataに値が入る。

# 同一セッション内でユーザーが2回目以降に訪れた場合
    1. 前回、取得した値がdataに入ると同時に取得が始まる。
    2. 取得が完了すると、dataには新しく取得したデータが入る。

したがって、先ほどの例の問題点を無事解決することができました。

他にも、プーリングによるデータの更新や画面フォーカス時での再取得など、自分で実装するとめんどくさい部分を全て吸収してくれいます。

また、サイズが11KBほどしかなく、小さいので嬉しいですね。

まとめと伝えたいこと

今回はswrの紹介と簡単な例を紹介させていただきました。

僕が伝えたかったこととしては、今後、脳死でreduxを採用する必要はなく、アプリケーションの要件にあったアーキテクチャを選択することができるようになったよ!ということです。

ちなみにこのswr、suspenseモードも有効化できるようでして、新しいreactアプリケーションのアーキテクチャにしっかり対応できるようになっていたりします。
まだ、v0.1.5ということもあり、今後の発展に期待ですね。