-
-
Notifications
You must be signed in to change notification settings - Fork 100
Expand file tree
/
Copy pathuseStore.ts
More file actions
45 lines (39 loc) · 1.15 KB
/
useStore.ts
File metadata and controls
45 lines (39 loc) · 1.15 KB
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
import { useCallback } from 'react'
import { useSyncExternalStoreWithSelector } from 'use-sync-external-store/shim/with-selector'
import type { AnyAtom } from '@tanstack/store'
type SyncExternalStoreSubscribe = Parameters<
typeof useSyncExternalStoreWithSelector
>[0]
/** Comparator using Object.is to correctly handle NaN and -0 edge cases. */
function defaultCompare<T>(a: T, b: T) {
return Object.is(a, b)
}
export function useStore<TAtom extends AnyAtom | undefined, T>(
atom: TAtom,
selector: (
snapshot: TAtom extends { get: () => infer TSnapshot }
? TSnapshot
: undefined,
) => T,
compare: (a: T, b: T) => boolean = defaultCompare,
): T {
const subscribe: SyncExternalStoreSubscribe = useCallback(
(handleStoreChange) => {
if (!atom) {
return () => {}
}
const { unsubscribe } = atom.subscribe(handleStoreChange)
return unsubscribe
},
[atom],
)
const boundGetSnapshot = useCallback(() => atom?.get(), [atom])
const selectedSnapshot = useSyncExternalStoreWithSelector(
subscribe,
boundGetSnapshot,
boundGetSnapshot,
selector,
compare,
)
return selectedSnapshot
}