UNPKG

@wener/console

Version:
58 lines (47 loc) 1.81 kB
import type { ReactNode } from 'react'; import { createElement, createContext as reactCreateContext, useContext, useMemo, useRef } from 'react'; import type { StoreApi } from 'zustand'; import { useStore } from 'zustand'; interface UseContextStore<S extends StoreApi<unknown>> { (): ExtractState<S>; <U>(selector: (state: ExtractState<S>) => U, equalityFn?: (a: U, b: U) => boolean): U; } type ExtractState<S> = S extends { getState: () => infer T } ? T : never; type WithoutCallSignature<T> = { [K in keyof T]: T[K] }; /** * v4 移除 * * @see https://github.com/pmndrs/zustand/discussions/1180 */ export function createStoreContext<S extends StoreApi<unknown>>() { const ZustandContext = reactCreateContext<S | undefined>(undefined); const Provider = ({ createStore, children }: { createStore: () => S; children: ReactNode }) => { const storeRef = useRef<S>(undefined); if (!storeRef.current) { storeRef.current = createStore(); } return createElement(ZustandContext.Provider, { value: storeRef.current }, children); }; const useContextStore: UseContextStore<S> = <StateSlice = ExtractState<S>>( selector?: (state: ExtractState<S>) => StateSlice, equalityFn?: (a: StateSlice, b: StateSlice) => boolean, ) => { const store = useContext(ZustandContext); if (!store) { throw new Error('Seems like you have not used zustand provider as an ancestor.'); } return useStore(store, selector as (state: ExtractState<S>) => StateSlice); }; const useStoreApi = () => { const store = useContext(ZustandContext); if (!store) { throw new Error('Seems like you have not used zustand provider as an ancestor.'); } return useMemo<WithoutCallSignature<S>>(() => ({ ...store }), [store]); }; return { Provider, useStore: useContextStore, useStoreApi, }; }