⚡
SWRはローカルの状態管理としても使える
SWRとは
SWRとはReactのためのデータフェッチライブラリです。
詳しい説明は省略しますが、リモートのデータ取得のためのキャッシュ機構を提供するライブラリとして知られています。
この記事では、そんなSWRが実はローカルの状態管理にも使用できることを紹介します。
Contextを使用する状態管理
通常は次のようにContext APIを使用することが多いでしょう。
import {
createContext,
ReactNode,
VFC,
useState,
Dispatch,
SetStateAction,
useContext,
} from 'react';
type ICountContext = {
count: number;
setCount: Dispatch<SetStateAction<number>>;
};
const CountContext = createContext<ICountContext>({
count: 0,
setCount: () => {},
});
type Props = {
children: ReactNode;
};
export const CountProvider: VFC<Props> = ({ children }) => {
const [count, setCount] = useState<number>(0);
return (
<CountContext.Provider value={{ count, setCount }}>
{children}
</CountContext.Provider>
);
};
export const useCountState = (): [
ICountContext['count'],
ICountContext['setCount']
] => {
const { count, setCount } = useContext(CountContext);
return [count, setCount];
};
import { AppProps } from 'next/app';
import { VFC } from 'react';
import { CountProvider } from '../context';
const MyApp: VFC<AppProps> = ({ Component, pageProps }) => {
return (
<CountProvider>
<Component {...pageProps} />;
</CountProvider>
);
};
export default MyApp;
SWRを使用した状態管理
同様の状態管理をSWRで書くと次のようになります。
export const useSWRCountState = (
initialCount: number
): [number, (count: number) => void] => {
const { data: count, mutate: setCount } = useSWR('count', null, {
initialData: initialCount,
});
return [count as number, setCount];
};
fetcher関数にnull
を渡してmutate
をsetState
の関数として使用しています。
そしてオプションのinitialData
に初期値を設定します。
このようにSWRを使うことで、簡単にグローバルなuseState
関数を作ることができました。
個人的にはRecoilと似たような状態管理ができて気に入っています。
ちなみに useSWR の引数には以下の4種類を渡すことができます。
参照
[cacheKey]
[cacheKey, fetcher]
[cacheKey, option]
[cacheKey, fetcher, option]
これを見るとfetcher関数にnullを渡さずに省略してもいい気がしますが、SWRはfetcher関数を省略すると次の関数がデフォルトで設定されます。https://github.com/vercel/swr/blob/11533ee8d5df6136726c4fc7a05bdbf1ac82fb35/src/libs/web-preset.ts#L22
const fetcher = (url: string) => fetch(url).then((res) => res.json());
なので、明示的にnullを渡しています。
先程のSWRを使用して簡単なサンプルコードを書いてみます。
cssは省略しています。
const SampleCount = () => {
const { data: count } = useSWR('count', null);
return <div>{count || 0}</div>;
};
const IndexPage: VFC = () => {
const [count, setCount] = useSWRCountState(0);
return (
<>
<div>{count}</div>
<div>
<SampleCount />
</div>
<div>
<Button onClick={() => setCount(count + 1)}>+1</Button>
</div>
</>
);
};
export default IndexPage;
問題なく動いていますね。
最後に
というわけでSWRはローカルの状態管理ライブラリとしても使用できます。
この方法は自分で思いついたわけではなく、SWRのソースコードを読んでいて知りました。
Discussion
貴重な情報有難うございます!
initialData: initialCount
の部分でエラーがでるようになってしまったのですが、何かご存知でしょうか?一度swrを1.0.1にアップグレードした影響かもしれません。
ダウングレードしてもエラーが消えなくなってしまいました。
追記:
したところ正常動作しました。
1.0.0以上から発生するエラーの様です。
initialDataはfallbackDataに置き換えられたようです!
サンプルコードのkeyを変更するとエラーが消えることを確認しました。(v1.0.0)
有難うございます!