Recoil と Local Storage のデータを共有させる方法

こんにちは。
イチマルイチデザインのフロントエンドエンジニアの高橋です。

今回は、Recoil と Local Storage のデータを共有させる方法を共有します。
言語は TypeScript です。

使用するライブラリ

Recoil とは

Facebook 製(現 Meta 社)の React 用の状態管理ライブラリです。

実装内容

まずはこちらが全体のコードです。

import { atom } from "recoil";
const LOCAL_STORAGE_KEY = "LOCAL_STORAGE_KEY";
const getToLocalStorage = () => {
  if (typeof window === "undefined") {
    return "";
  }
  const value = window.localStorage.getItem(LOCAL_STORAGE_KEY);
  return value ? JSON.parse(value) : "";
};
const saveToLocalStorage = (value: string) => {
  if (typeof window === "undefined") {
    return;
  }
  window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(value));
};
export const recoilWithLocalStorage = atom<string>({
  key: "recoilWithLocalStorage",
  default: getToLocalStorage(),
  effects_UNSTABLE: [
    ({ onSet }) => {
      onSet((newValue) => {
        saveToLocalStorage(newValue);
      });
    },
  ],
});

以下、解説となります。

if (typeof window === "undefined") {
  return "";
}

window オブジェクトの未定義エラー回避のため、関数式 `getToLocalStorage` と関数式 `saveToLocalStorage`
内で `typeof window === 'undefined'`を条件としてif文を定義しています。

const getToLocalStorage = () => {
  if (typeof window === "undefined") {
    return "";
  }
  const value = window.localStorage.getItem(LOCAL_STORAGE_KEY);
  return value ? JSON.parse(value) : "";
};

Local Storage から値を取得するための関数式です。
Local Storage に値がない場合、空の文字列を返します。
(※今回は値の型は `String` とします。)

const saveToLocalStorage = (value: string) => {
  if (typeof window === "undefined") {
    return;
  }
  window.localStorage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(value));
};

引数として渡された値を Local Storage にセットする関数式です。

export const recoilWithLocalStorage = atom<string>({
  key: "recoilWithLocalStorage",
  default: getToLocalStorage(),
  effects_UNSTABLE: [
    ({ onSet }) => {
      onSet((newValue) => {
        saveToLocalStorage(newValue);
      });
    },
  ],
});

Recoil の `atom` を定義します。
デフォルトの値として、`getToLocalStorage` から取得した値を `default`として設定します。
`effects_UNSTABLE` に新しい値がセットされたタイミングで `saveToLocalStorage` に新しい値を渡す処理を設定することで、Recoil のデータストア側の値と Local Storage の値を同時に更新して、実質的にデータを共有しているような実装が可能となります。

使い方

import React from "react";
import { useRecoilState } from "recoil";
export const MyComponent = () => {
  const [value, setValue] = useRecoilState(recoilWithLocalStorage);
};

`useRecoilState` や `useRecoilValue` などの Recoil が提供しているカスタムフックの引数に定義したストアを渡すことで、`RecoilRoot`内であればどこのコンポーネントからでもステートの呼び出しやセットが可能となります。

終わりに

株式会社イチマルイチデザインでは、私たちと一緒に React・Next.js、TypeScript などの技術を使った WEB アプリケーションや WEB サイトの開発をするフロントエンドエンジニアの仲間を募集しています。

デザイナーやバックエンドエンジニアの方も募集をしておりますので、興味がある方はご連絡お待ちしております。

▼採用サイトはこちら
https://101de-sign.com/recruit