React ReduxではなくRecoilを使用


開発開始当初は、グローバルステータス管理が必要ということは知らなかったのですが、各種プロジェクトを行う際に必要性を意識し、反応に含まれるContext API、最もよく使われるReduxを通して、今回はRecoilを使うことにしました.Reactを作成したMeta(当時のFacebook)が開発したライブラリですが、周囲からはState Hookとの使い方があまり違わないと言われていたので試してみました.

基本的な使い方


最も基本的な構成要素は、atomおよびselectorである.

atom

atomは一般的に考えられている状態と似ている.
const textState = atom({
  key: 'textState', // 고유한 식별자
  default: '', // 기본값 (혹은 초기값)
});
前述したようにdefaultで指定した値を使用して初期化します.keyは一意でなければなりません.同じkeyを持つatomまたはセレクタがある場合、エラーが発生します.
使用時は以下のようになります.
const [text, setText] = useRecoilState(textState);
State Hookと使い方がよく似ていることがわかります.違いは、生成(atom)のみと使用(useRecoilState)が別々であることである.

selector

selectorは、既に存在する原子または他の値を用いて派生値を生成することができる.
const charCountState = selector({
  key: 'charCountState', // 고유한 식별자
  get: ({get}) => {
    const text = get(textState);

    return text.length;
  },
});
atomと同様ですが、defaultではなくgetを定義します.getは、セレクタ呼び出し時に返される値を定義する関数をパラメータとして受け入れます.この関数は、パラメータとしてget関数を使用して別の原子の値を取得するか、別の値を使用して新しい値を生成して返します.
ここではselectorが読み取り専用かどうか知りたいかもしれませんが、実際にはできます.セレクタを定義する場合は、setを一緒に定義できます.getは必要ですがsetではありません.
const proxySelector = selector({
  key: 'ProxySelector',
  get: ({get}) => ({...get(myAtom), extraField: 'hi'}),
  set: ({set}, newValue) => set(myAtom, newValue),
});
atomのset関数は既存のstateを受信パラメータの値に完全に置き換え、selectorのset関数はパラメータを受信し、これらのパラメータと既存の値を使用して新しい状態を設定します.上記の例ではnewValueをmyAtomに設定していますが、他のatomの値を使用して派生値を設定することもできます.

Hooks


ここでは、AtomとSelectorを使用する際に必要なHooksについて説明します.

useRecoilValue


まず、値のみがロードされているUserRecolValueについて説明します.
const count = useRecoilValue(charCountState);
const proxy = useRecoilValue(proxySelector);
読み取り専用の値を返します.この値を使用する構成部品または関数が値を購読します.値が変化すると、サブスクリプションの構成部品が更新されます.

useRecoilState


userRecoilStateは、ReactのState Hookのように値と書き込み可能な関数を返します.
const [count, setCount] = useRecoilState(charCountState);
const [proxy, setProxy] = useRecoilState(proxySelector);
この場合、set関数が定義されていない場合、セレクタはuserRecoilstateと一緒に使用できません.書き込み可能な関数が定義されていないためです.

const tempFahrenheit = atom({
  key: 'tempFahrenheit',
  default: 32,
});

const tempCelcius = selector({
  key: 'tempCelcius',
  get: ({get}) => ((get(tempFahrenheit) - 32) * 5) / 9,
  set: ({set}, newValue) =>
    set(tempFahrenheit, (newValue * 9) / 5 + 32)
});

const [tempF, setTempF] = useRecoilState(tempFahrenheit);
const [tempC, setTempC] = useRecoilState(tempCelsius);
上記の例は、華氏と燮氏を変換するatomとselectorである.tempCelciusのget関数はtempFahrenheitの値を使用してソルビンを計算し、set関数は入力したnewValueを使用して華氏度を計算し、格納します.
tempCelciusは、tempFahreitから派生した値であるため、tempFahreitを購読します.したがって、setTempF関数を使用して華氏度を変更する場合は、userEffectなどの他のhookを使用する必要はなく、tempCは変更した値を自動的に反映します.

残念な点


これにより、RecoilはState Hookのように使いやすくなります.しかし、残念なこともある.不変性を維持するには、リストを含むオブジェクトはset関数に新しいオブジェクトを渡す必要がありますが、深さが2より大きいと、深さのコピーが非常に面倒になります.Recoilの開発者もatomのように元の値や簡単な値を保存することをお勧めします.

...Atomまたはセレクタはサブスクリプションの最小単位であるため、元の値または単純な値を表すためにAtomを使用することを推奨します.ただし、これらの事実が重要でない場合や面倒な場合は、atomに豊富なオブジェクトを格納できます.
ソース
Redux-toolkitのcreateSliceは、ユーザーのアイデンティティや現在のトピックなどの単純な値を格納するのに制限はありませんが、深さが2より大きい複雑なオブジェクトの方が使いやすいです.
それでもRecoilは誕生して間もない新生ライブラリ(2020年5月に初提出)であり、Meta自身が作成したライブラリであり、今後の発展の余地も大きい.

ソース


Recoil公式ドキュメント