-
-
Notifications
You must be signed in to change notification settings - Fork 100
Expand file tree
/
Copy pathindex.tsx
More file actions
124 lines (105 loc) · 2.94 KB
/
index.tsx
File metadata and controls
124 lines (105 loc) · 2.94 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
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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
import { createSignal, onCleanup } from 'solid-js'
import type { Derived, Store } from '@tanstack/store'
import type { Accessor } from 'solid-js'
export * from '@tanstack/store'
/**
* @private
*/
export type NoInfer<T> = [T][T extends any ? 0 : never]
export function useStore<TState, TSelected = NoInfer<TState>>(
store: Store<TState, any>,
selector?: (state: NoInfer<TState>) => TSelected,
): Accessor<TSelected>
export function useStore<TState, TSelected = NoInfer<TState>>(
store: Derived<TState, any>,
selector?: (state: NoInfer<TState>) => TSelected,
): Accessor<TSelected>
export function useStore<TState, TSelected = NoInfer<TState>>(
store: Store<TState, any> | Derived<TState, any>,
selector: (state: NoInfer<TState>) => TSelected = (d) => d as any,
): Accessor<TSelected> {
const [signal, setSignal] = createSignal(selector(store.state))
const unsub = store.subscribe(() => {
const data = selector(store.state)
if (shallow(signal(), data)) {
return
}
setSignal(() => data)
})
onCleanup(() => {
unsub()
})
return signal
}
export function shallow<T>(objA: T, objB: T) {
if (Object.is(objA, objB)) {
return true
}
if (
typeof objA !== 'object' ||
objA === null ||
typeof objB !== 'object' ||
objB === null
) {
return false
}
if (objA instanceof Map && objB instanceof Map) {
if (objA.size !== objB.size) return false
for (const [k, v] of objA) {
if (!objB.has(k) || !Object.is(v, objB.get(k))) return false
}
return true
}
if (objA instanceof Set && objB instanceof Set) {
if (objA.size !== objB.size) return false
for (const v of objA) {
if (!objB.has(v)) return false
}
return true
}
if (objA instanceof Date && objB instanceof Date) {
if (objA.getTime() !== objB.getTime()) return false
return true
}
const keysA = Object.keys(objA)
const keysB = Object.keys(objB)
if (keysA.length !== keysB.length) {
return false
}
if (keysA.length > 0) {
for (const key of keysA) {
if (
!Object.prototype.hasOwnProperty.call(objB, key) ||
!Object.is(objA[key as keyof T], objB[key as keyof T])
) {
return false
}
}
return true
}
if (keysA.length === 0) {
const descriptorsA = Object.getOwnPropertyDescriptors(objA)
const descriptorsB = Object.getOwnPropertyDescriptors(objB)
const getterKeysA = Object.keys(descriptorsA).filter(
(key) => descriptorsA[key]?.get !== undefined,
)
const getterKeysB = Object.keys(descriptorsB).filter(
(key) => descriptorsB[key]?.get !== undefined,
)
if (getterKeysA.length !== getterKeysB.length) {
return false
}
for (const key of getterKeysA) {
if (
!getterKeysB.includes(key) ||
!Object.is(
(objA as Record<string, unknown>)[key],
(objB as Record<string, unknown>)[key],
)
) {
return false
}
}
}
return true
}