🌲

フォルダの構造を利用してRecoilのkeyを管理する手法

2023/05/07に公開

フォルダ構造を利用して key 名を管理する

Recoil 導入時に頭を悩ませたのが、atom や selector の key の名称をアプリケーションで一意に保つことでした。どうにかして簡単に管理することが出来ないかと思案しているとき、ふとフォルダ構造を利用する方法に思い至りました。

例えば、API から取得したユーザーの情報を Recoil で管理するとします。ユーザー情報には、名前や住所といったユーザーの個人情報が含まれています。このとき、ユーザーの名前や住所を selector で管理する場合のキー名はどうするでしょうか。直感的にはuser.name user.addressといったキー名が思い浮かぶと考えます。
このキーの名前をフォルダの構造に一致させることができれば、一意なキー値を保てるだろうというのが、この記事で提案する手法の大本になる考え方です。

大まかなまとめ

https://github.com/SiroSuzume/recoil-key-management-example/tree/main/src/recoil に example をいれた

全てのフォルダに key.ts を格納する

src/recoil以下の全てのフォルダに、key.tsという名前のキー管理用ファイルを配置するのをルールとします。親フォルダの key.ts を参照し、結合することでキーを一意に保つことができます。
また、キーの結合時にSetを使った重複チェック処理を挟み、ケアレスミスによるキーの重複が発生しても、実行時エラーが起きるようにします。

キーを生成する関数の example

src/recoil/index.ts
const generatedKeys = new Set<string>()

export function generateRecoilKey(parentKey: string, suffix: string): string {
  const key = `${parentKey}.${suffix}`
  if (generatedKeys.has(key)) throw new Error(`${key} is already exists`)
  generatedKeys.add(key)
  return key
}

key.tsの example

src/recoil/key.ts
// これより上の階層にkey.tsはない
const key = 'recoil'
export default key
src/recoil/user/key.ts
import { generateRecoilKey } 'src/recoil'
import parentKey from '../key'
// 親フォルダのキーと結合する
const key = generateRecoilKey(parentKey, 'user')
export default key
// src/recoil/user/index.ts
import { atom } from "recoil";
import key from "./key";

export const userAtom = atom<UserModel | undefined>({
  key,
  default: undefined,
});

Hygen を使って生成する

key.tsのルールを守るため、recoil の atom or selector を作る際は、hygen を利用して生成できるようにします。具体例はこちらのリポジトリに作成しました。
https://github.com/SiroSuzume/recoil-key-management-example/tree/main/_templates/recoil/new

おわりに

間違ってたらごめんなさい!
eslint等でkeyの名前とフォルダ名が一致していなければ、エラーを出す等のルールを追加すると、より確実に守る事ができると思います。

Discussion