Recoilを使ってみる。
Recoilとは
RecoilはMeta社が開発している、
Reactとの互換性が高いステートマネージングフレームワークになります。
グローバルステートを管理する事ができます。
主な機能
atom
Storeとしての役割
実際に共通データとして保持しておく場所になります。
文字列や配列、オブジェクトなどを格納しておく事ができます。
Recoilでは基本的にkeyは一つのatomと一対一になる必要があるので、
こちらのkeyを一意にしておく必要があります。
const todoListState = atom({
key: 'TodoList',
default: [],
});
上記で言うと、todoを格納していく配列になります。
こちらに保存されてる情報がコンポーネントを跨いで、各所から読み込む事ができます。
selector
取得のGetとしての役割
少し変わっているところとして、getプロパティなどで、getを引数として受け取るというところです。
setプロパティも同じように、getやsetを引数として受け取ることができます。
selectorは、atomのデータを取得するのに整形した形で返すために使います。
複数のatomからデータを取得する事ができます。
上記に合わせて、以下の形で取得します。
const todoListFilterState = atom({
key: 'TodoListFilter',
default: 'Show All',
});
const filteredTodoListState = selector({
key: 'FilteredTodoList',
get: ({get}) => {
const filter = get(todoListFilterState);
const list = get(todoListState);
switch (filter) {
case 'Show Completed':
return list.filter((item) => item.isComplete);
case 'Show Uncompleted':
return list.filter((item) => !item.isComplete);
default:
return list;
}
},
});
上記では、todoListFilterStateの値によって、取得できるtodoが異なるように
取得できるものを変更させる事ができます。
この他にも、情報を付与して取得するようにも取得できます。
const getPrice = selector({
key: 'getPrice',
get: ({ get }) => {
const price = get(priceState)
return `${price}円`
}
})
selectorにはsetパラメータもあります。
これは新しい値を受け取ることで、setで新しい値を適応させることができます。
const tempFahrenheit = atom({
key: 'tempFahrenheit',
default: 32,
});
const tempFahrenheit = atom({
key: 'tempFahrenheit',
default: 32,
});
const tempCelsius = selector({
key: 'tempCelsius',
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);
const addTenCelsius = () => setTempC(tempC + 10);
const addTenFahrenheit = () => setTempF(tempF + 10);
ここでは、tempC + 10
とtempF + 10
がnewValueに入ってくることで、
新しい値に変換してくれている感じです。
setプロパティの中でもgetを使うことができるので、別のatomを注入することも可能です。
family
atomFamilyとselectorFamilyがあります。
パラメータを受け取り、その返り値を決める事ができます。
atomFamilyは、パラメータを受け取り、そのパラメータによってデフォルト値を変えることができますが、基本的にはatomと変わらない形で使えます。
const myAtomFamily = atomFamily({
key: ‘MyAtom’,
default: param => defaultBasedOnParam(param),
});
selectorFamilyは、atomFamilyと同様にパラメータを受け取ることができます。
他のatomに依存した値をデフォルトに指定する時に使います。
この時、selectorFamilyに対してのkeyも指定する必要がある点に注意が必要です。
const myAtomFamily = atomFamily({
key: ‘MyAtom’,
default: selectorFamily({
key: 'MyAtom/Default',
get: param => ({get}) => {
const otherAtomValue = get(otherState);
return computeDefaultUsingParam(otherAtomValue, param);
},
}),
});
感想
個人的に良さそうなstate管理フレームワークだと思いました。
特に複雑なことを考えずに、呼び出し元のコンポーネントのみのレンダリングになるという点や
複数のatom stateへのアクセスの便利性は現在あるようなstate管理より簡略的に書けたりするのでスッキリとしたコードになるかなという印象を持ちました。
ただ、どのような設計にするかは結構分かれると思うので、プロダクトに対する設計の仕方は少し難しいような気もしました。
まだプロダクトで使用した訳ではないので、これから使っていく中で分かったことがあれば、追記できたらいいなと思います。
参考
Discussion