🐣

チーム開発でRecoilを良い感じに使う(ベストプラクティス?)

2022/10/29に公開1

はじめに

今回は「俺が考えた最強のRecoilの使い方」を紹介します
Recoilのベストプラクティスを紹介する記事が見当たらなかったので書いてみました
既出でしたら申し訳ありません

間違いや改善点、疑問点等ありましたら是非コメントでご指摘ください

注意

本記事はRecoil修得済みの方向けの記事になります
Recoilなんもわからんな方は是非以下の記事をご覧ください(Recoilはいいぞ)

https://zenn.dev/nekoniki/articles/406087e43f4865

1.サンプルアプリ

今回は数字を保存する状態hogeStateを加工したhogeStrStateを表示するアプリを例にとります
create-react-appを使用して作成したプロジェクトです


左右のボタンによりインクリメント・デクリメントが可能

2.ディレクトリ構成

src
├── components
~省略~
└── recoil
    ├── {State名}
    |   ├── index.ts
    |   ├── states.ts
    |   ├── (types.ts)
    |   └── {Module名}.ts
    └── recoilKeys.ts
 
※ State名 = {Key}State
※ Module名 = {State名(先頭大文字)}Module

3.Keyの管理

まずはKey(atom等のプロパティであるkey)の管理です

重複が許されないKeyはrecoilKeys.tsで一元管理します
配列のままだと使用時にindexを指定しなければいけなくなるので、Key: Keyのオブジェクトに加工してexportしています

recoilKeys.ts
// Keyの配列
const recoilKeys = [
 "hoge",
 "hogeStr",
 "fuga",
 "piyo",
] as const

// Key: Keyのオブジェクト
export const recoilKeyHashSet = Object.fromEntries(
  recoilKeys.map((k) => [k, k])
) as {
  [k in typeof recoilKeys[number]]: k;
};

// 重複チェック
const set = new Set(recoilKeys);
if (set.size !== recoilKeys.length) {
  throw Error("recoilKeyが重複しています");
}

4.ディレクトリ構成の詳細と実装

状態の配置

src
├── components
~省略~
└── recoil
    ├── hogeState
    └── recoilKeys.ts

State(atom, selector等状態の総称)はsrc/recoil/直下にフォルダを作り実装します

この時依存関係があるStateは同じディレクトリに纏めます
そのためrecoil/atom/hogeStaterecoil/selector/hogeStrStateといったようなディレクトリ分けは不要になります

状態の実装

hogeState
├── index.ts
├── states.ts
├── (types.ts)
└── HogeStateModule.ts

index.ts

ルーターみたいなものです
import文を綺麗にするため纏めてexportします

index.ts
export * from "./state"
export * from "./HogeStateModule"

states.ts

atom等を作成しexportします
加工した値を提供したい時はselectorを作成しexportしましょう

型が複雑な場合、types.tsに型定義を移すといいかもしれません

state.ts
export const hogeState = atom<number>({
  key: recoilKeyHashSet.hoge,
  default: 0
});

export const hogeStrState = selector<string>({
  key: recoilKeyHashSet.hogeStr,
  get: ({get}) => ` hogeState: ${get(hogeState)} `
});

(types.ts)

Stateに関する型を定義します

HogeStateModule.ts

関連する全てのStateの書き込み関数を提供するModuleを作成します
Stateが意図しない変更を防ぎ、実装を集約する意図です

モジュール名は、対象のState群の中でメインのStateのState名(先頭大文字)+ Module、と命名します

コンポーネント外でStateを変更するため、Recoil Nexusというライブラリを使用します

HogeStateModule.ts
export const HogeStateModule = {
  increment: () => setRecoil(hogeState, (pre) => pre + 1),
  decrement: () => setRecoil(hogeState, (pre => pre - 1))
}

5.使用

StateはuseRecoilValuegetRecoilなどの関数を使い取得します

App.ts
import {HogeStateModule, hogeStrState} from './recoil/hogeState';

function App() {
  const hogeStr = useRecoilValue(hogeStrState);

  return (
    <div className="App">
      <header className="App-header">
        <button onClick={HogeStateModule.decrement}>-</button>
        {hogeStr}
        <button onClick={HogeStateModule.increment}>+</button>
      </header>
    </div>
  );
}

6.おわりに

チーム開発でRecoilを使う時のベストプラクティス?でした
今見返すと、一元的に管理することに重点を置いてることに気付きました

皆様のRecoilライフがより快適になれば嬉しいです
最後までお読み頂きありがとうございました!!

Discussion

Teruhisa - T6ADEVTeruhisa - T6ADEV

記事ありがとうございます!
個人的な見解をこちらでまとめてみました、参考になれば幸いです。