1 | import { produce } from 'immer';
|
2 | import { atom, useAtom } from 'jotai';
|
3 | import { useCallback } from 'react';
|
4 |
|
5 | function atomWithImmer(initialValue) {
|
6 | const anAtom = atom(initialValue, (get, set, fn) => set(anAtom, produce(get(anAtom), (draft) => fn(draft))));
|
7 | return anAtom;
|
8 | }
|
9 |
|
10 | function useImmerAtom(anAtom) {
|
11 | const [state, setState] = useAtom(anAtom);
|
12 | const setStateWithImmer = useCallback((fn) => {
|
13 | setState(produce((draft) => fn(draft)));
|
14 | }, [setState]);
|
15 | return [state, setStateWithImmer];
|
16 | }
|
17 |
|
18 | const getWeakCacheItem = (cache, deps) => {
|
19 | const [dep, ...rest] = deps;
|
20 | const entry = cache.get(dep);
|
21 | if (!entry) {
|
22 | return;
|
23 | }
|
24 | if (!rest.length) {
|
25 | return entry[1];
|
26 | }
|
27 | return getWeakCacheItem(entry[0], rest);
|
28 | };
|
29 | const setWeakCacheItem = (cache, deps, item) => {
|
30 | const [dep, ...rest] = deps;
|
31 | let entry = cache.get(dep);
|
32 | if (!entry) {
|
33 | entry = [new WeakMap()];
|
34 | cache.set(dep, entry);
|
35 | }
|
36 | if (!rest.length) {
|
37 | entry[1] = item;
|
38 | return;
|
39 | }
|
40 | setWeakCacheItem(entry[0], rest, item);
|
41 | };
|
42 |
|
43 | const withImmerCache = new WeakMap();
|
44 | function withImmer(anAtom) {
|
45 | const deps = [anAtom];
|
46 | const cachedAtom = getWeakCacheItem(withImmerCache, deps);
|
47 | if (cachedAtom) {
|
48 | return cachedAtom;
|
49 | }
|
50 | const derivedAtom = atom((get) => get(anAtom), (get, set, fn) => set(anAtom, produce(get(anAtom), (draft) => fn(draft))));
|
51 | derivedAtom.scope = anAtom.scope;
|
52 | setWeakCacheItem(withImmerCache, deps, derivedAtom);
|
53 | return derivedAtom;
|
54 | }
|
55 |
|
56 | export { atomWithImmer, useImmerAtom, withImmer };
|