LoginSignup
1
0

More than 1 year has passed since last update.

Recoilで簡単なフィルター機能を実装

Last updated at Posted at 2022-02-19

デモ(codesandbox)

今回使用したコードです → Demo

Recoilとは

meta社が開発したグローバルな状態管理をできるライブラリです。

正式リリースされたばかりだが、シンプルに状態管理をしていけるので最近注目度が高いです。
実際コードが少なく書けるので見通しもよいかと思います。
初学者でRedux使っていないので、どこがどう違って、なにが良くてなにが良くないか分からないですが。。。

インストール

まずパッケージのインストールをします。typescriptの場合は型定義もインストール忘れずに。

npm i recoil
npm i @types/recoil

RecoilRootでコンポーネントをwrapする

Recoilで状態管理する場合、そのグローバルな状態管理をする範囲をRecoilRootで囲む必要があります。プロジェクト全体を範囲とする場合、大元のをwrapします。

import { render } from "react-dom";
import { RecoilRoot } from "recoil";

import App from "./App";
//Recoilを利用するコンポーネントをRecoilRootでwrapする
const rootElement = document.getElementById("root");
render(
  <RecoilRoot>
    <App />
  </RecoilRoot>,
  rootElement
);

atomの定義

グローバルStateとして扱いたいデータをatomとして定義する。

今回は男女でフィルターかけようと思うので、このような初期値を定義します。keyは一意のものを使用してください。コピペでファイル作成したときにkeyだけ変更し忘れて同じkeyができてしまってバグになっていたことがあります。

atomの定義はこれだけでグローバルなstateとして管理できます。非常にシンプル。

import { atom } from "recoil";

type personType = { name: string; gender: string };

const person: personType[] = [
  { name: "yamada", gender: "male" },
  { name: "sato", gender: "female" }
];
//keyは一意のものを設定する
//defaultプロパティに初期値をセットするだけ
export const persons = atom({
  key: "person",
  default: person
});
//これでpersonsはグローバルなStateとして管理できる

atomの使い方

atomを使いたい場合はuseRecoilStateを使います。定義の仕方はuseStateと同じ。setの仕方も同じですので非常に簡単に使えます。

import { useRecoilState } from "recoil";
import { persons } from "./Atom";

export default function App() {
  //useStateと同じように定義し、初期値をatomとする
  const [personsArray, setPersonsArray] = useRecoilState(persons);
  console.log(personsArray);
  //[Object, Object]
 
  const onClickSet = () => {
    //Stateの更新もuseStateのときと同じようにできる
    setPersonsArray([...personsArray, { name: "suzuki", gender: "male" }]);
  };
  console.log(personsArray);
  // [Object, Object, Object]

  return <button onClick={onClickSet}>ボタン</button>;
}

用途に分けて
const personsArray = useRecoilValueとすると読み取り専用で定義ができます。
const setPersonsArray=useSetRecoilStateとすると書き込み専用の定義ができます。

selectorの定義

selectorはatomを加工した値をstateとして利用することができます。
atomが更新されるとselectorも更新がかかります。今回はfilter関数を使ってatomを男女に分けたselectorを作成します。

import { selector } from "recoil";
import { persons } from "./Atom";

//getで取得したpersonsをfilter関数でmaleのみ抽出
export const malesSelector = selector({
  key: "males",
  get: ({ get }) => {
    const males = get(persons).filter((item) => {
      return item.gender === "male";
    });
    return males;
  }
});

//同様にfemaleのみ抽出
export const femalesSelector = selector({
  key: "females",
  get: ({ get }) => {
    const females = get(persons).filter((item) => {
      return item.gender === "female";
    });
    return females;
  }
});

このようにgetプロパティ内でatomを取得して何かしらの処理で値を加工できます。
returnした値が定義したselectorの値としてグローバルに読み取ることができます。
この場合のselectorは読み取り専用となります。
setプロパティはオプションであるのですが、この記事では割愛。

selectorの読み込みとフィルター機能の実装

全体としてはこんな感じです。

(1)のようにuseRecoilValueを使ってatomのように取得できます。

あとはそれぞれの配列をmapで繰り返してリスト表示します。
どれを表示するかは別のstateを定義して、レンダリングの条件分岐などで表示を制御すれば、簡単なフィルター分けを実装できます。
条件分岐は&&を使って簡単に書いてます。

export default function App() {
  //useStateと同じように定義し、初期値をatomとする
  const [personsArray, setPersonsArray] = useRecoilState(persons);
  console.log(personsArray);
  //[Object, Object]

  const onClickSet = () => {
    //Stateの更新もuseStateのときと同じようにできる
    setPersonsArray([...personsArray, { name: "suzuki", gender: "male" }]);
  };
  console.log(personsArray);
  // [Object, Object, Object]

  //定義したselectorはatomと同じように取得できる・・・(1)
  const malesArray = useRecoilValue(malesSelector);
  const femalesArray = useRecoilValue(femalesSelector);
  //ボタンを押したときのshowState
  const [showList, setShowList] = useState<string>("");

  const onClickAll = () => {
    setShowList("all");
  };
  const onClickMale = () => {
    setShowList("male");
  };
  const onClickFemale = () => {
    setShowList("female");
  };

  //レンダーの条件分岐は && を使用
  //&&の左側がtrueなら右側を評価する
  //map関数で配列を繰り返してリスト表示する
  return (
    <>
      <button onClick={onClickSet}>鈴木(男)を追加</button>
      <button onClick={onClickAll}>全て表示</button>
      <button onClick={onClickMale}>maleのみ表示</button>
      <button onClick={onClickFemale}>femaleのみ表示</button>
      {showList === "all" &&
        personsArray.map((item) => {
          return (
            <div>
              <ul>
                <li>{item.name}</li>
              </ul>
            </div>
          );
        })}
      {showList === "male" &&
        malesArray.map((item) => {
          return (
            <div>
              <ul>
                <li>{item.name}</li>
              </ul>
            </div>
          );
        })}
      {showList === "female" &&
        femalesArray.map((item) => {
          return (
            <div>
              <ul>
                <li>{item.name}</li>
              </ul>
            </div>
          );
        })}
    </>
  );
}

atomが追加や変更で更新された時のみselectorも更新されるので、その辺も特に意識する必要がなくとても簡単。
atomとselectorだけでも色々できるので、もし誰かの学習の参考になれば幸いです。

1
0
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
0