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> { (): ExtractState; (selector: (state: ExtractState) => U, equalityFn?: (a: U, b: U) => boolean): U; } type ExtractState = S extends { getState: () => infer T } ? T : never; type WithoutCallSignature = { [K in keyof T]: T[K] }; /** * v4 移除 * * @see https://github.com/pmndrs/zustand/discussions/1180 */ export function createStoreContext>() { const ZustandContext = reactCreateContext(undefined); const Provider = ({ createStore, children }: { createStore: () => S; children: ReactNode }) => { const storeRef = useRef(undefined); if (!storeRef.current) { storeRef.current = createStore(); } return createElement(ZustandContext.Provider, { value: storeRef.current }, children); }; const useContextStore: UseContextStore = >( selector?: (state: ExtractState) => 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) => 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>(() => ({ ...store }), [store]); }; return { Provider, useStore: useContextStore, useStoreApi, }; }