1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

便利な状態管理ライブラリRecoilを使ってみる

Posted at

筆者はこれまで、Reactの状態管理を行う場合は下記のものを利用してきました。

  • PropsでのStateのバケツリレー
  • Contextを利用したコンポーネントツリー内の受け渡し
  • Reduxをもちいた一元管理で堅牢な状態管理

それぞれメリット・デメリットがあり、プロジェクトの規模や状況に応じて使い分けが必要だと感じました。

Contextのように手軽に使えてかつ、パフォーマンスが良く、Reduxのようにコードの分離が可能でかつ、学習難易度が低い、曖昧な表現ですが「ちょうどいい」状態管理ライブラリがほしいなと感じていました。そこでRecoilのことを知り、まさにその要望を満たす状態管理ライブラリなのでは無いかと思い、今回触ってみることにしました。

Recoilの特徴

Recoilは、パフォーマンスの不安を解消しつつ、コードの分離が可能で、(使うだけなら)学習難易度が低めな状態管理ライブラリです。

主に、共有するStateであるatomと、selectorと呼ばれるatomや他のselectorを受け取る純粋関数を利用します。

公式サイトのコアコンセプトページに基本的な使い方が乗っているので、それを見るとわかりやすいと思います。

この記事でも大雑把に説明します。

Atoms

const fontSizeState = atom({
  key: 'fontSizeState',
  default: 14,
});

atom関数を使ってatomを作成します。

keyはその名の通りatomのキーです。他のatomと被らないように一意な値を指定します。

defaultはatomが管理するStateの初期値です。

const [fontSize, setFontSize] = useRecoilState(fontSizeState);

コンポーネントでこのStateを取得するためにはuseRecoilState関数を利用します。引数に、先程作成したatomであるfontSizeStateを指定します。[fontSize, setFontSize]を見てわかるように、useStateのような使い方で、コンポーネントをまたいでStateを取得・変更することができます。

Selectors

const fontSizeLabelState = selector({
  key: 'fontSizeLabelState',
  get: ({get}) => {
    const fontSize = get(fontSizeState);
    const unit = 'px';

    return `${fontSize}${unit}`;
  },
});

selector関数を使ってselectorを作成します。

keyは同じく一意な値である必要があります。

getは実行される関数です。getを引数にとっていますが、このget関数を利用することで他のatomやselectorにアクセスできるようになります。

アクセスしているatomやselectorが更新された場合、getは再計算され最新の値となります。

実際につかってみる

まずはReactのプロジェクトを作る

$ npx create-react-app recoil
$ cd recoil

recoilをインストール

$ npm install recoil

RecoilRootで大本のコンポーネントを囲う

index.js
...
import { RecoilRoot } from "recoil";
...
root.render(
  <React.StrictMode>
    <RecoilRoot>
      <App />
    </RecoilRoot>
  </React.StrictMode>
);
...

atomとselectorを作成する

App.js
import { atom, selector, useRecoilState, useRecoilValue } from "recoil";

const textState = atom({
  key: "textState",
  default: "",
});

const charCountState = selector({
  key: "charCountState",
  get: ({ get }) => {
    const text = get(textState);

    return text.length;
  },
});
...

それぞれrecoilのatom, selectorを利用するコンポーネントを作成する

  • テキスト入力を受け付けるコンポーネント
  • 入力されたテキストの文字数を表示するコンポーネント
App.js
function TextInput() {
  const [text, setText] = useRecoilState(textState);

  const onChange = (event) => {
    setText(event.target.value);
  };

  return (
    <div>
      <input type="text" value={text} onChange={onChange} />
    </div>
  );
}

function CharacterCount() {
  const count = useRecoilValue(charCountState);

  return <>Character Count: {count}</>;
}

Appコンポーネントから呼び出す

App.js
function App() {
  return (
    <div className="App">
      <TextInput />
      <CharacterCount />
    </div>
  );
}

これで環境を立ち上げると状態がちゃんと管理できていることがわかる

スクリーンショット 2022-07-12 19.43.37.png

Appコンポーネントからstateを受け渡す記述もなく、コードが非常にスッキリしています。

また、Contextと違い、コードを描くときにほとんど意識することなく、無関係なコンポーネントの再レンダリングが抑えられています。

終わりに

Recoilは利用するだけなら学習難度が低く、また無駄な再レンダリングを起こすコードを書いてしまう可能性が他の状態管理ライブラリくらべて低い、非常にバランスの取れたライブラリだと感じました。これからは積極的に使っていこうと思います!

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?