SWR 触ってみた
こんにちは開発チームの笠原です。
社内で SWR の活用を検討しており、その過程でドキュメントをさよっと読んでサンプルを触ってみた感想を記事にました。
SWR の特徴
SWR とはデータ取得と React コンポーネントの状態を管理するための Hooks をまとめたライブラリです。
たった 1 行のコードで、プロジェクト内のデータ取得のロジックを単純化し、さらにこれらの素晴らしい機能をすぐに利用できるようになります:
- 速い、 軽量 そして 再利用可能 なデータの取得
- 組み込みの キャッシュ とリクエストの重複排除
- リアルタイム な体験
- トランスポートとプロトコルにとらわれない
- SSR / ISR / SSG support
- TypeScript 対応
- React Native
引用:https://swr.vercel.app/ja#%E7%89%B9%E5%BE%B4
似たライブラリとして React Query があります。 個人的に SWR の方が短く書けるので好みなのと、今後 Next.js と組み合わせて使うことを想定しているので Vercel が開発している SWR のほうが親和性が高いかなと考えています。
データの取得
Next.js でのサンプルです。
useUser.ts
import useSWR from 'swr';
import { fetcher } from '../fetch';
import { User } from '../types';
export const useUser = (userId: string) => {
const { data, error } = useSWR(`/api/users/${userId}`, fetcher);
return {
user: data,
isLoading: !error && !data,
isError: error
}
}
index.tsx
import type { NextPage } from 'next'
import { useUser } from '../hooks/useUser'
const Home: NextPage = () => {
const { data, error } = useSWR<User, Error>(`/api/users/${userId}`, fetcher);
if (isLoading) {
return <div>loading...</div>
}
if (isError) {
return <div>Error: ${isError.message}</div>
}
return (
<div>
<p>ID : {user?.id}</p>
<p>NAME : {user?.name}</p>
</div>
)
}
export default Home
useSWR()
は hooks にラップしてコンポーネントからデータの取得を分離することで、保守性が高まります。
useUser()
の第1引数が key となり, 第2引数 fetcher にはデータをフェッチするための Promise を返す関数を渡すだけです。
これだけだとあまりメリットは感じられませんが、SWR の魅力的なところはキャッシュです。
上記の Home ページに2度目にアクセスした際には key が同じであれば1度目に fetch したキャッシュが使われます。 第3引数の options でポーリングなど自動再検証の設定も変更できます。
気になったポイント
データのフェッチやその他の機能については公式のドキュメントに詳しく書かれているので詳しくは書きませんでした。 ただ「これどうすんだろう」というポイントがいくつかあったのでピックアップしました。
1. データフェッチ用カスタムフックのテスト方法
たとえば上記の useUser()
をテストしたいときにどうするか悩みました。
ぱっと思いつくのは jest.mock('swr')
として useState()
の戻り値を mock することです。
別の方法として SWR の middleware を使う方法を紹介している記事を見つけました。
middleware を利用することで SWR 以外の機能で mock しないので予期しない不具合がおきづらいと考えらます。 ※middleware でデータに前処理を行っているだけ
詳しくはこちら:https://zenn.dev/terrierscript/articles/2021-12-08-swr-middleware-non-mock-test
2. 状態管理ライブラリとして使う
冒頭でも述べましたが、SWR は状態管理も行えます。 以下のように書くことで Recoil のようなグローバルな useState 関数を使うことができます。
useSWR()
の第2引数に null
を渡せば fetch を行わない。
export const useCounter = (initialCount: number): [number, (count: number) => void] => {
const { data: count, mutate: setCount } = useSWR('count', null, {
initialData: initialCount,
});
return [count as number, setCount];
};
SWR での状態管理はこちらの記事がとても参考になりました。 https://zenn.dev/itizawa/articles/9f71e1f636d3d2
まとめ
この記事では本当に一部しか触れていませんが、SWR には「条件付きフェッチ」「プリフェッチ」「ページング」などなどアプリを開発していれば必要になる機能が揃っています。 まだ使ったことが無いというかたは楽しいのでぜひ触ってみてください。
CURUCURU では新しい技術やサービス作りが好きなエンジニアを募集中です! 「ITで女性のライフスタイルを豊かにする」というミッションの元やりがいのあるサービス作りに携わる事ができます。
CURUCURU でエンジニアとして働くことに興味がある方はよければオンラインでカジュアルにお話しましょう! https://www.wantedly.com/companies/curucuru/projects