-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.ts
43 lines (41 loc) · 1.46 KB
/
index.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
import { useEffect, useMemo, useReducer } from 'react';
import type { ReducerWithoutAction } from 'react';
import { subscribe, snapshot } from 'valtio/vanilla';
import type { Snapshot } from 'valtio/vanilla';
import { createProxy, isChanged } from 'proxy-compare';
const targetCache = new WeakMap();
export function useValtio<State extends object>(proxy: State): Snapshot<State> {
// per-proxy & per-hook affected, it's not ideal but memo compatible
// eslint-disable-next-line react-hooks/exhaustive-deps
const affected = useMemo(() => new WeakMap<object, unknown>(), [proxy]);
const [[snapshotFromReducer, proxyFromReducer], rerender] = useReducer<
ReducerWithoutAction<readonly [Snapshot<State>, State]>,
undefined
>(
(prev) => {
const nextSnapshot = snapshot(proxy);
if (
prev[1] === proxy &&
!isChanged(prev[0], nextSnapshot, affected, new WeakMap())
) {
// not changed
return prev;
}
return [nextSnapshot, proxy];
},
undefined,
() => [snapshot(proxy), proxy],
);
let snapshotToReturn = snapshotFromReducer;
if (proxyFromReducer !== proxy) {
rerender();
snapshotToReturn = snapshot(proxy);
}
useEffect(() => {
const unsubscribe = subscribe(proxy, rerender, true);
rerender();
return unsubscribe;
}, [proxy]);
const proxyCache = useMemo(() => new WeakMap(), []); // per-hook proxyCache
return createProxy(snapshotToReturn, affected, proxyCache, targetCache);
}