semigraphy

個人の意見です

RecoilのAtomをlocalStorageに保存して読み込む

注意点

  • より良いやり方があると思うので教えてください
  • AtomEffectは使っていません(今後試す予定)

TL;DR

  • setIntervalで1000ms毎に状態を取得して保存
  • RecoilRootのinitializeState に渡して読み込む

環境

Next.js 12.0.7 + Recoil 0.5.2

本題

Atoms の用意

atoms/states.ts

import { atom } from "recoil";

export const activityListState = atom<{ id: string; date: number | Date }[]>({
  key: "activityListState",
  default: [],
});

export const taskListState = atom<string[]>({
  key: "taskListState",
  default: [],
});
  • activityListState, taskListState の2つを用意

保存

pages/sandbox.tsx

import { useEffect } from "react";

import { useRecoilState } from "recoil";

import { activityListState, taskListState } from "../atoms/states";

function Sandbox() {
  const [taskList] = useRecoilState(taskListState);
  const [activityList] = useRecoilState(activityListState);

  useEffect(() => {
    const interval = setInterval(() => {
      if (
        localStorage.getItem("activityListState") !==
        JSON.stringify(activityList)
      ) {
        localStorage.setItem("activityListState", JSON.stringify(activityList));
      }
      if (localStorage.getItem("taskListState") !== JSON.stringify(taskList)) {
        localStorage.setItem("taskListState", JSON.stringify(taskList));
      }
    }, 1000);
    return () => clearInterval(interval);
  }, [activityList, taskList]);

  return <div />;
}

export default Sandbox;
  • useEffect内でsetIntervalを使用してstateの変更を取得しsetItemしている

読み込み

_app.tsx

import { useEffect, useState } from "react";

import type { AppProps } from "next/app";
import { RecoilRoot } from "recoil";

import { activityListState, taskListState } from "../atoms/states";

function MyApp({ Component, pageProps }: AppProps) {
  const [taskList, setTaskList] = useState([]);
  const [activityList, setActivityList] = useState([]);

  useEffect(() => {
    setTaskList(JSON.parse(localStorage.getItem("taskListState") || "[]"));
    setActivityList(
      JSON.parse(localStorage.getItem("activityListState") || "[]")
    );
  }, []);

  return (
    <RecoilRoot
      initializeState={(mutableSnapshot) => {
        mutableSnapshot.set(activityListState, activityList);
        mutableSnapshot.set(taskListState, taskList);
      }}
    >
      <Component {...pageProps} />
    </RecoilRoot>
  );
}

export default MyApp;
  • initializeStateとmutableSnapshotというものを使ってlocalStorageの値をatomsの初期stateに入れる。

参考ドキュメント