use-zustand
Version:
Another custom hook to use Zustand vanilla store
49 lines (47 loc) • 1.39 kB
text/typescript
import { useEffect, useReducer } from 'react';
import type { DispatchWithoutAction, Reducer } from 'react';
import type { StoreApi } from 'zustand';
export function useZustand<State, Slice>(
store: StoreApi<State>,
selector: (state: State) => Slice,
areEqual: (a: Slice, b: Slice) => boolean = Object.is,
) {
const state = store.getState();
const [[sliceFromReducer, storeFromReducer], rerender] = useReducer<
Reducer<
readonly [Slice, StoreApi<State>, State],
readonly [Slice, StoreApi<State>, State] | undefined
>,
undefined
>(
(prev, fromSelf) => {
if (fromSelf) {
return fromSelf;
}
const nextState = store.getState();
if (Object.is(prev[2], nextState) && prev[1] === store) {
return prev;
}
const nextSlice = selector(nextState);
if (areEqual(prev[0], nextSlice) && prev[1] === store) {
return prev;
}
return [nextSlice, store, nextState];
},
undefined,
() => [selector(state), store, state],
);
useEffect(() => {
const unsubscribe = store.subscribe(() =>
(rerender as DispatchWithoutAction)(),
);
(rerender as DispatchWithoutAction)();
return unsubscribe;
}, [store]);
if (storeFromReducer !== store) {
const slice = selector(state);
rerender([slice, store, state]);
return slice;
}
return sliceFromReducer;
}