🃏

Picking From 20 React State Managersが素晴らしい、例題コードのJotaiとRecoilの違いが明確

2022/01/07に公開

https://twitter.com/dai_shi/status/1479080774246989826

Jack HerringtonさんのYouTubeチャンネルの動画はどれも素晴らしいのですが、今回のビデオはだいぶ見応えがありました。状態管理ライブラリの比較に興味がある方はぜひご覧ください。

https://www.youtube.com/watch?v=P95DuIBwnqw

Atomicモデルについては、ビデオの中ではRecoilを中心に説明しているのですが、JackさんはJotaiを好んでくださっていて、ビデオの最後でも言及してくれています。

リポジトリには全部のコードが載せられています。

https://github.com/jherr/which-react-state-manager

特に気になったのがJotaiのコードです。普段JotaiはRecoilの軽量版と認識されたり説明されたりすることが多いのですが、背景や細かい違いは多分にあります。未だにうまく説明する方法を模索中なのですが、このリポジトリではそれぞれのコードが明確に違ったので興味深いです。

リポジトリからstore.tsxをだけを引用して載せます。

Recoilの例題コード

atomic-recoilのstore.tsxから転載

import { useEffect } from "react";
import {
  atom,
  useRecoilState,
  useSetRecoilState,
  useRecoilValue,
  selector,
} from "recoil";

const namesValueAtom = atom<string[] | undefined>({
  key: "namesValue",
  default: undefined,
});

export const secondsAtom = atom({ key: "seconds", default: 0 });

export const namesAtom = selector({
  key: "namesAtom",
  get: ({ get }) => (get(secondsAtom) > 2.0 ? get(namesValueAtom) : ""),
});

export const runningAtom = atom({ key: "running", default: false });

export const useStopwatch = () => {
  const [seconds, setSeconds] = useRecoilState(secondsAtom);
  const setNames = useSetRecoilState(namesValueAtom);
  const running = useRecoilValue(runningAtom);

  useEffect(() => {
    if (seconds > 2) {
      fetch("/names.json")
        .then((res) => res.json())
        .then(({ names }) => setNames(names));
    }
  }, [seconds > 2]);

  useEffect(() => {
    if (running) {
      const interval = window.setInterval(() => {
        setSeconds((seconds) => seconds + 0.1);
      }, 100);
      return () => clearInterval(interval);
    }
  }, [running]);
};

Jotaiの例題コード

atomic-jotaiのstore.tsxから転載

import { atom } from "jotai";

export const namesAtom = atom<string[] | undefined>(undefined);

export const secondsAtom = atom(0);

const incrementSecondsAtom = atom(
  (get) => get(secondsAtom),
  async (get, set, amount: number) => {
    set(secondsAtom, get(secondsAtom) + amount);

    if (get(secondsAtom) > 2 && !get(namesAtom)) {
      const response = await fetch("/names.json");
      set(namesAtom, (await response.json()).names);
    }
  }
);

const timerRefAtom = atom<number | undefined>(undefined);

export const runningAtom = atom(
  (get) => get(timerRefAtom) !== undefined,
  (get, set, start: boolean) => {
    if (get(timerRefAtom) !== undefined) {
      clearInterval(get(timerRefAtom));
      set(timerRefAtom, undefined);
    }

    if (start) {
      set(
        timerRefAtom,
        window.setInterval(() => {
          set(incrementSecondsAtom, 0.1);
        }, 100)
      );
    }
    return get(timerRefAtom) !== undefined;
  }
);

Jotaiを使ってRecoilのようなコードを書くこともできるはずですが、このコードはとてもJotai流に書かれています。軽い驚きとともにとても参考になりました。自分でもこのような比較コードを作らなければ。ちなみに、RecoilでJotai流に書けるかどうかは知りません。

Jotaiのサイト

https://jotai.org

Discussion