Skip to content

Commit 897e7fd

Browse files
Check individual selected values
1 parent 2a7f072 commit 897e7fd

File tree

1 file changed

+27
-10
lines changed

1 file changed

+27
-10
lines changed

src/store/hooks/useStateStore.ts

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ const noop = () => {};
77

88
export function useStateStore<
99
T extends Record<string, unknown>,
10-
O extends Readonly<Record<string, unknown> | Readonly<unknown[]>>
10+
O extends Readonly<Record<string, unknown> | Readonly<unknown[]>>,
1111
>(store: StateStore<T>, selector: (v: T) => O): O;
1212
export function useStateStore<
1313
T extends Record<string, unknown>,
14-
O extends Readonly<Record<string, unknown> | Readonly<unknown[]>>
14+
O extends Readonly<Record<string, unknown> | Readonly<unknown[]>>,
1515
>(store: StateStore<T> | undefined, selector: (v: T) => O): O | undefined;
1616
export function useStateStore<
1717
T extends Record<string, unknown>,
18-
O extends Readonly<Record<string, unknown> | Readonly<unknown[]>>
18+
O extends Readonly<Record<string, unknown> | Readonly<unknown[]>>,
1919
>(store: StateStore<T> | undefined, selector: (v: T) => O) {
2020
const wrappedSubscription = useCallback(
2121
(onStoreChange: () => void) => {
@@ -26,18 +26,35 @@ export function useStateStore<
2626
);
2727

2828
const wrappedSnapshot = useMemo(() => {
29-
let cached: [T, O];
29+
let cachedTuple: [T, O];
30+
3031
return () => {
31-
const current = store?.getLatestValue();
32+
const currentValue = store?.getLatestValue();
33+
34+
if (!currentValue) return undefined;
35+
36+
// store value hasn't changed, no need to compare individual values
37+
if (cachedTuple && cachedTuple[0] === currentValue) {
38+
return cachedTuple[1];
39+
}
40+
41+
const newlySelected = selector(currentValue);
42+
43+
// store value changed but selected values wouldn't have to, double-check selected
44+
if (cachedTuple) {
45+
let selectededAreEqualToCached = true;
3246

33-
if (!current) return undefined;
47+
for (const key in cachedTuple[1]) {
48+
if (cachedTuple[1][key] === newlySelected[key]) continue;
49+
selectededAreEqualToCached = false;
50+
break;
51+
}
3452

35-
if (!cached || cached[0] !== current) {
36-
cached = [current, selector(current)];
37-
return cached[1];
53+
if (selectededAreEqualToCached) return cachedTuple[1];
3854
}
3955

40-
return cached[1];
56+
cachedTuple = [currentValue, newlySelected];
57+
return cachedTuple[1];
4158
};
4259
}, [store, selector]);
4360

0 commit comments

Comments
 (0)