zukucode
主にWEB関連の情報を技術メモとして発信しています。

React RecoilでグローバルなStateを作成する

React+TypeScriptの環境で、Recoilを使用して、グローバルな状態State(グローバル変数)を作成します。

React createContextでグローバルなStateを作成するcreateContextを使用したグローバル変数を作成しましたが、Recoilを使えばもっとシンプルにグローバル変数作成できます。

パッケージのインストール

まずはRecoilのパッケージをインストールします。

$ npm install recoil

ルートコンポーネントの修正

以下のように、ルートコンポーネントにRecoilRootを追加します。

RecoilRootの子コンポーネントの全てで、Recoilのグローバル変数が使用できるようになります。

import { RecoilRoot } from 'recoil';

const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
  <React.StrictMode>
    <RecoilRoot>
      <App />
    </RecoilRoot>
  </React.StrictMode>
);

atomの作成

Recoilではグローバル変数はatomを使用して作成します。

import { atom } from 'recoil';

const loadingState = atom<boolean>({
  key: 'loadingState', // プロジェクト全体でユニークとなる値
  default: false,
});

atom<型>の形式でグローバル変数を定義します。

keyにはプロジェクト全体でユニークとなる値を設定します。

規模が大きいプロジェクトの場合はkeyの値は別ファイルで管理したほうが良いかと思います。

defaultには初期値を設定します。

カスタムフックの作成

作成したatomuseRecoilState(atom変数)で参照します。

各コンポーネントでuseRecoilStateで参照する形でも問題ありませんが、ここではカスタムフックを作成します。

グローバル変数のゲッター、セッターだけではなく、グローバル変数を使用した共通処理もグローバルファンクションとして一緒に定義することが多いと思うので、カスタムフックとして定義しておき、各コンポーネントでカスタムフックを経由して使用します。

useApp.tsx
import { useCallback } from 'react';
import { atom, useRecoilState } from 'recoil';

const loadingState = atom<boolean>({
  key: 'loadingState', // プロジェクト全体でユニークとなる値
  default: false,
});

export const useLoading = () => {
  const [loading, setLoading] = useRecoilState(loadingState);

  return {
    loading,
    setLoading,
    toggleLoading: useCallback(() => {
      setLoading((current) => !current);
    }, [setLoading]), // 必要に応じて独自のファンクションも追加
  };
};

useRecoilStateuseStateと同じように[ゲッター, セッター]の形で使用できます。

使い方

以下のように使用します。

カスタムフックを経由して参照すれば、React createContextでグローバルなStateを作成するで紹介したcontextを使用する場合と同じ方法で参照することができます。

MyComponent.tsx
import useApp from './useApp';

const MyComponent = () => {
  // recoilの値を参照可能
  const { loading, setLoading } = useApp();
};

関連記事