forked from pmndrs/zustand
-
Notifications
You must be signed in to change notification settings - Fork 0
/
context.ts
102 lines (90 loc) · 2.6 KB
/
context.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// import {
// createElement,
// createContext as reactCreateContext,
// useContext,
// useMemo,
// useRef,
// } from 'react'
// That doesnt work in ESM, because React libs are CJS only.
// The following is a workaround until ESM is supported.
// eslint-disable-next-line import/extensions
import ReactExports from 'react'
import type { ReactNode } from 'react'
import type { StoreApi } from 'zustand'
// eslint-disable-next-line import/extensions
import { useStoreWithEqualityFn } from 'zustand/traditional'
const {
createElement,
createContext: reactCreateContext,
useContext,
useMemo,
useRef,
} = ReactExports
type 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] }
/**
* @deprecated Use `createStore` and `useStore` for context usage
*/
function createContext<S extends StoreApi<unknown>>() {
if (import.meta.env?.MODE !== 'production') {
console.warn(
"[DEPRECATED] `context` will be removed in a future version. Instead use `import { createStore, useStore } from 'zustand'`. See: https://github.com/pmndrs/zustand/discussions/1180.",
)
}
const ZustandContext = reactCreateContext<S | undefined>(undefined)
const Provider = ({
createStore,
children,
}: {
createStore: () => S
children: ReactNode
}) => {
const storeRef = useRef<S>()
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 useStoreWithEqualityFn(
store,
selector as (state: ExtractState<S>) => StateSlice,
equalityFn,
)
}
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,
}
}
export default createContext