フォルダの構造を利用してRecoilのkeyを管理する手法
フォルダ構造を利用して 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 の名前にしてしまう
- hygen テンプレートを使用して atom や selector の追加を行う
全てのフォルダに key.ts を格納する
src/recoil
以下の全てのフォルダに、key.ts
という名前のキー管理用ファイルを配置するのをルールとします。親フォルダの key.ts を参照し、結合することでキーを一意に保つことができます。
また、キーの結合時にSet
を使った重複チェック処理を挟み、ケアレスミスによるキーの重複が発生しても、実行時エラーが起きるようにします。
キーを生成する関数の example
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
// これより上の階層にkey.tsはない
const key = 'recoil'
export default key
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 を利用して生成できるようにします。具体例はこちらのリポジトリに作成しました。
おわりに
間違ってたらごめんなさい!
eslint等でkeyの名前とフォルダ名が一致していなければ、エラーを出す等のルールを追加すると、より確実に守る事ができると思います。
Discussion