Reactの状態管理ライブラリRecoilを使ってみる

フロントエンドは、よくVueを使っているプロジェクトにいることが多いのですが、ここ最近は個人の時間でReactを勉強していました。状態管理ライブラリを探していたところRecoilというものがあることを知り、少し触れてみました。

この記事ではAtomの使い方について、簡単に書いておこうかと思います。

https://recoiljs.org/docs/introduction/core-concepts#atoms

環境

viteを使いプロジェクトを作成します。React + TypeScript のテンプレートを指定しています。

npm create vite@latest recoil-my-playground -- --template react-ts

ディレクトリに移動して、Recoilをインストールします。

npm install recoil

package.json の中身は次のとおりです。これを書いている時点でのRecoilのバージョンは、0.7.7 でした。

{
  "name": "recoil-my-playground",
  "private": true,
  "version": "0.0.0",
  "type": "module",
  "scripts": {
    "dev": "vite",
    "build": "tsc -b && vite build",
    "lint": "eslint .",
    "preview": "vite preview"
  },
  "dependencies": {
    "react": "^18.3.1",
    "react-dom": "^18.3.1",
    "recoil": "^0.7.7"
  },
  "devDependencies": {
    "@eslint/js": "^9.8.0",
    "@types/react": "^18.3.3",
    "@types/react-dom": "^18.3.0",
    "@vitejs/plugin-react": "^4.3.1",
    "eslint": "^9.8.0",
    "eslint-plugin-react-hooks": "^5.1.0-rc.0",
    "eslint-plugin-react-refresh": "^0.4.9",
    "globals": "^15.9.0",
    "typescript": "^5.5.3",
    "typescript-eslint": "^8.0.0",
    "vite": "^5.4.0"
  }
}

atom を定義する

atomは状態の最小限単位です(名前からも最小単位であることが想像しやすいですね)。Recoilではatomを定義し、Reactコンポーネントatomの値を読み込み/書き込みすることができるようになっています。

atomは次のように定義できます。

import { atom } from "recoil";

export const helloTypographyState = atom<string>({
  key: "helloTypographyState",
  default: "this is read from recoil atom",
});

ここでは、helloTypographyState を定義しました。このatomはstring型の値を保持し、デフォルトが this is read from recoil atomとしています。Reactコンポーネントはこの値にアクセスすることができます。

atom を読み込む

atomを読み込むにはuseRecoilValueを使います。useStateと同じ感じです。

上記のatomを読み込んで画面に表示するコンポーネントは次のように実装できます。

import { useRecoilValue } from "recoil";
import { helloTypographyState } from "../store/HelloTypographyState";

export function HelloTypography() {
  const helloTypography = useRecoilValue(helloTypographyState);
  return <h1>Hello, {helloTypography}</h1>;
}

atomを使うことでコンポーネントが表示する文字列を、コンポーネントから切り離して管理することができました。

atom を書き込む

atomを書き込むにはuseSetRecoilStateを使います。

次のButtonChangeHelloTypographyコンポーネントでは、先ほど定義した helloTypographyStateをChangeに変更します。

import { useSetRecoilState } from "recoil";
import { helloTypographyState } from "../store/HelloTypographyState";

export function ButtonChangeHelloTypography() {
  const setHelloTypography = useSetRecoilState(helloTypographyState);
  return <button onClick={() => setHelloTypography("Change")}>Change</button>;
}

これで、同じatomを共有する2つのReactコンポーネントを定義することができました。atomの値は変化が起きると値を読み込んでいるコンポーネントは最新の値で再レンダリングされる仕組みになっています。そのため、atomを書き込むコンポーネントatomの値をどのように変更すればよいかだけに注力すればよく、再レンダリングをしなければならないReactコンポーネントや、再レンダリングのタイミングはRecoilが管理してくれます。