mirror of
https://github.com/pmndrs/zustand.git
synced 2025-12-08 19:45:52 +00:00
105 lines
3.2 KiB
TypeScript
105 lines
3.2 KiB
TypeScript
// import { useDebugValue } from 'react'
|
|
// import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector'
|
|
// Those don't work in ESM, because React libs are CJS only.
|
|
// See: https://github.com/pmndrs/valtio/issues/452
|
|
// The following is a workaround until ESM is supported.
|
|
// eslint-disable-next-line import/extensions
|
|
import ReactExports from 'react'
|
|
// eslint-disable-next-line import/extensions
|
|
import useSyncExternalStoreExports from 'use-sync-external-store/shim/with-selector'
|
|
import { createStore } from './vanilla.ts'
|
|
import type {
|
|
Mutate,
|
|
StateCreator,
|
|
StoreApi,
|
|
StoreMutatorIdentifier,
|
|
} from './vanilla.ts'
|
|
|
|
const { useDebugValue } = ReactExports
|
|
const { useSyncExternalStoreWithSelector } = useSyncExternalStoreExports
|
|
|
|
type ExtractState<S> = S extends { getState: () => infer T } ? T : never
|
|
|
|
type ReadonlyStoreApi<T> = Pick<StoreApi<T>, 'getState' | 'subscribe'>
|
|
|
|
type WithReact<S extends ReadonlyStoreApi<unknown>> = S & {
|
|
/** @deprecated please use api.getState() */
|
|
getServerState?: () => ExtractState<S>
|
|
}
|
|
|
|
const identity = <T>(arg: T): T => arg
|
|
|
|
export function useStoreWithEqualityFn<S extends WithReact<StoreApi<unknown>>>(
|
|
api: S,
|
|
): ExtractState<S>
|
|
|
|
export function useStoreWithEqualityFn<
|
|
S extends WithReact<StoreApi<unknown>>,
|
|
U,
|
|
>(
|
|
api: S,
|
|
selector: (state: ExtractState<S>) => U,
|
|
equalityFn?: (a: U, b: U) => boolean,
|
|
): U
|
|
|
|
export function useStoreWithEqualityFn<TState, StateSlice>(
|
|
api: WithReact<StoreApi<TState>>,
|
|
selector: (state: TState) => StateSlice = identity as any,
|
|
equalityFn?: (a: StateSlice, b: StateSlice) => boolean,
|
|
) {
|
|
const slice = useSyncExternalStoreWithSelector(
|
|
api.subscribe,
|
|
api.getState,
|
|
api.getServerState || api.getInitialState,
|
|
selector,
|
|
equalityFn,
|
|
)
|
|
useDebugValue(slice)
|
|
return slice
|
|
}
|
|
|
|
export type UseBoundStoreWithEqualityFn<
|
|
S extends WithReact<ReadonlyStoreApi<unknown>>,
|
|
> = {
|
|
(): ExtractState<S>
|
|
<U>(
|
|
selector: (state: ExtractState<S>) => U,
|
|
equalityFn?: (a: U, b: U) => boolean,
|
|
): U
|
|
} & S
|
|
|
|
type CreateWithEqualityFn = {
|
|
<T, Mos extends [StoreMutatorIdentifier, unknown][] = []>(
|
|
initializer: StateCreator<T, [], Mos>,
|
|
defaultEqualityFn?: <U>(a: U, b: U) => boolean,
|
|
): UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>
|
|
<T>(): <Mos extends [StoreMutatorIdentifier, unknown][] = []>(
|
|
initializer: StateCreator<T, [], Mos>,
|
|
defaultEqualityFn?: <U>(a: U, b: U) => boolean,
|
|
) => UseBoundStoreWithEqualityFn<Mutate<StoreApi<T>, Mos>>
|
|
}
|
|
|
|
const createWithEqualityFnImpl = <T>(
|
|
createState: StateCreator<T, [], []>,
|
|
defaultEqualityFn?: <U>(a: U, b: U) => boolean,
|
|
) => {
|
|
const api = createStore(createState)
|
|
|
|
const useBoundStoreWithEqualityFn: any = (
|
|
selector?: any,
|
|
equalityFn = defaultEqualityFn,
|
|
) => useStoreWithEqualityFn(api, selector, equalityFn)
|
|
|
|
Object.assign(useBoundStoreWithEqualityFn, api)
|
|
|
|
return useBoundStoreWithEqualityFn
|
|
}
|
|
|
|
export const createWithEqualityFn = (<T>(
|
|
createState: StateCreator<T, [], []> | undefined,
|
|
defaultEqualityFn?: <U>(a: U, b: U) => boolean,
|
|
) =>
|
|
createState
|
|
? createWithEqualityFnImpl(createState, defaultEqualityFn)
|
|
: createWithEqualityFnImpl) as CreateWithEqualityFn
|