主にプログラミング関連のメモ帳 ♪(✿╹ヮ╹)ノ
書いてあるコードは自己責任でご自由にどうぞ。記事本文の無断転載は禁止です。
2022/10/02
個人的に最近よく使っている React のステート管理ライブラリである Recoil と、外部ストレージ (DB や URL) などとステートを同期するライブラリ Recoil Sync を使って、 LocalStorage にデータを保存しようという記事です。
ということで、いつも通り準備。
Recoil Sync を使うので、パッケージマネージャー経由で入れます。
このとき、 eslint-plugin-import を使っている場合は、 @recoiljs/refine
も追加してあげる必要があります。
$ yarn add recoil-sync
追加したら、まずは LocalStorage と同期するための RecoilSync
コンポーネントを作成します。
基本的には Implementing a Store と同様の実装をすれば問題ありません。
今回の場合は、以下のようになると思います。
import React from "react";
import { ItemKey, RecoilSync, WriteInterface } from "recoil-sync";
import useLocalStorage from "../hooks/useLocalStorage"; // この実装をそのまま使用 → https://usehooks.com/useLocalStorage/
type Props = {
children: React.ReactNode;
};
const RecoilSyncWithLocalStorage: React.FC<Props> = ({ children }) => {
const [value, setValue] = useLocalStorage(
"natsuneko.moe", // LocalStorage のキー (お好きにどうぞ)
{
/* 初期データを入れる */
}
);
const read = (key: ItemKey) => {
return value[key] ?? null;
};
const write = (state: WriteInterface) => {
const { diff } = state;
for (const [k, v] of diff) {
value[k] = v;
}
setValue(value);
};
// StoreKey には、 RecoilSync 毎にユニークなキーを指定する
return (
<RecoilSync storeKey="LocalStorage" read={read} write={write}>
{children}
</RecoilSync>
);
};
次に、これを RecoilRoot
直下などに突っ込みます。
この辺は、他の Recoil Sync を使う使い方と同じです。
// some component
return (
<RecoilRoot>
<RecoilSyncWithLocalStorage>{/* ... */}</RecoilSyncWithLocalStorage>
</RecoilRoot>
);
あとは、 Recoil の atom
で定義を入れてあげれば OK です。簡単ですね。
import { number, string } from "@recoiljs/refine";
import { atom } from "recoil";
import { syncEffect } from "recoil-sync";
type SomeState = {
a: number;
b: string;
};
const state = atom<SomeState>({
key: "state",
default: undefined, // ここは使われない (初期ステートにも Recoil Sync で引っぱってきたデータが使用される)
effects: [
syncEffect({
storeKey: "LocalStorage", // 同期に使用する StoreKey、今回の場合は RecoilSyncWithLocalStorage で指定したキー
itemKey: "state", // アイテム毎のキー, これが read および write で渡される
refine: {
a: number(),
b: string(),
},
}),
],
});
とまぁ、こんな感じの実装で、簡単に LocalStorage にデータを半永続化することができます。
ということで、メモでした。