Jotaiとは
Jotai, primitive and flexible state management for React
React用の状態管理ライブラリ。
いいところ
1. 状態キャッシュと依存計算の最適化
ReactでいうuseMemoやuseEffectの第二引数のように、依存関係となる変数を明示した上で計算結果のキャッシュ(/computed property)を構築することができる。
具体的には、以下のようにgetter , setter に独自の記法が採用されている。
// 基準値
const sampleAtom = atom<number>(0)
const sampleAtom2 = atom<number>(2)
// get
// sampleAtomやsampleAtom2の情報が変わらない限り再計算されない
const getSampleAtom = atom<number>(get => {
if (get(sampleAtom) > 2.0 ) {
return get(sampleAtom2)
}
return get(sampleAtom)
})
// set
// 様々なルールが指定できる
const setSampleAtomByValue = atom<null , number /*imput */>(null , (get , set , val)=>{
if (get(getSampleAtom) < val ) {
set(sampleAtom , val)
return
}
set(sampleAtom , get(sampleAtom2))
})
//便宜上変数を分けているが、両方記載することも可能。
特にgetterの場合、get引数で取得する値がJotaiの管理化=atomである場合に、それらが依存関係にあるとみなされ、依存先の状態が変化するまでは再計算を防ぐことができる。
また、これらの計算はReactのRenderフェーズに依存せずに連鎖的に依存に応じた各種計算ができるため、チラつき等の軽減にも役立つかもしれない。
2. setとgetの分離による最適化
React側から使うときは大抵の場合、
useAtom(get/set)
, useAtomValue(get)
, useSetAtom(set)
あたりを使うことになる。useAtomValue
, useSetAtom
をうまく使うと、値を入れ込みたいコンポーネントと値を表示したいコンポーネントでそれぞれに仮想DOMの再計算を防ぐことができる。
下記の例では、セッターのみを持つSample2Tsx
は再計算されない。
// 表示用
export const SampleAtomTsx = ()=> {
const val = useAtomValue(sampleAtom)
return (
<div>
{val}
</div>
)
}
// 入力用
const Sample2Tsx = ()=> {
const setVal = useSetAtom(sampleAtom)
return (
<div>
<button onClick={() => setVal(prev => prev+1)} >+</button>
</div>
)
}
const App = ()=> {
return (
<>
<SampleAtomTsx />
<Sample2Tsx />
</>
)
}
3. Providerレスで雑に使える
上記例に見るようにいらない。便利。
難しいところ
大域オブジェクトというよりは、細かく値を扱う/ 影響を持つコンポーネントを分離することによって再計算を防ぐための真価を発揮する。
だがこの 「細かく扱う」 というところに実際どうしたらいいの?という悩みが発生している。
jotaiというよりはjotaiによって「できるようになること」をキレイに活かすためにどうしたらいいんだ?という類の悩みだが…。
1. APIが自由すぎて、jotaiを知らないと扱えるか謎
export const useSampleAtom = ()=> {
const getSample = useAtomValue(sampleAtom)
const setSample = useSetAtom(setSampleAtom)
return {
getSample,
setSample,
}
}
useAtom , useSetAtom , useAtomValue
を使い手に意識させたくなくてたとえばこんな隠蔽をしたとしよう。
これだとsetSampleを使ったときにはgetSampleも必ず動いちゃう(仮想DOMが走っちゃう)ので、jotaiの良いところをうまく活かせない気もしていてうまくない。
2. 細かくは扱えるが…そんなに最適化って要るんだっけ
大域オブジェクトというよりは、細かく値を扱うことによって真価を発揮するが、最適化のためにあちこちのコンポーネントがそれぞれ個別のStore的なものにアクセスすると、治安が悪くなるという話がある。
これももちろんjotaiのせいでなく、「jotaiによってできるようになったこと」に対する悩みである。
大抵の場合はめちゃめちゃ最適化しなくても、そこそこでかい単位のオブジェクトベースで管理しちゃっていいかな、と思ってはいる。
export type State = {
offset: number;
zoom: number;
zoomMax: number;
x: number;
y: number;
};
const stateAtoms = atom<State>({
offset: 0,
zoom: 0,
zoomMax: 100,
x: 0,
y: 100,
});