Open8
Zustandメモ
Reduxのようにグローバルなstoreを操作する.しかしstate, reducer, actioin, selector, dispatcherなどに分かれておらず,stateにメソッドのような形でreducer (action) を定義してstoreを作成する.
import { create } from "zustand";
type State = {
count: number;
};
type Action = {
countUp: () => void;
};
type Store = State & Action;
const useStore = create<Store>()((set) => ({
// stateの初期値
count: 0,
// set() で受け取るアロー関数でstateを更新する
// アロー関数の引数は現在のstate
// アロー関数の戻り値のオブジェクトのプロパティがstateに差分として書き加えられる
countUp: () => set((state) => ({ count: state.count + 1 })),
}));
// create()の戻り値がselectorのhookとなっている
const count = useStore((state) => state.count);
const countUp = useStore((state) => state.countUp);
<button type="button" onClick={countUp}>{count}</button>
1アプリケーションに複数のstoreを保持できる.
storeにactionを紐付ける点で、1つのstoreとreducerで全てのイベントを扱うReduxの考えとは異なる.
Fluxに近い?
Slice pattern
小さなstore (slice) をマージして大きなstoreを作る.slice間の状態に応じたactionも定義可能.
Sample
type AgeSlice = {
age: number;
grow: () => void;
};
const createAgeSlice: StateCreator<
AgeSlice & NameSlice,
[],
[],
AgeSlice
> = (set, get) => ({
age: 20,
grow: () => set({ age: get().age + 1 }),
});
type NameSlice = {
name: string;
};
const createNameSlice: StateCreator<
AgeSlice & NameSlice,
[],
[],
NameSlice
> = () => ({
name: "Taro",
});
type SharedSlice = {
func: () => void;
};
const createSharedSlice: StateCreator<
AgeSlice & NameSlice,
[],
[],
SharedSlice
> = (_, get) => ({
func: () => {
get().grow();
},
});
const useStore = create<AgeSlice & NameSlice & SharedSlice>()((...a) => ({
...createAgeSlice(...a),
...createNameSlice(...a),
...createSharedSlice(...a),
}));
store間で依存関係がある場合はsliceパターンでより大きなstoreとしてまとめて管理することが推奨のようだ.