swr-global-state
Version:
Zero-setup & simple global state management for React Components
144 lines (143 loc) • 3.81 kB
JavaScript
import { useMemo as P, useRef as J, useState as N, useCallback as w, useEffect as j } from "react";
import k, { useSWRConfig as x } from "swr";
function H(r, c) {
let t;
return { debouncedFunc: (...n) => {
clearTimeout(t), t = setTimeout(() => r(...n), c);
}, cleanup: () => {
clearTimeout(t);
} };
}
function K(r, c) {
let t = 0, u;
return { throttledFunc: (...a) => {
const o = Date.now();
o - t >= c ? (t = o, r(...a)) : (clearTimeout(u), u = setTimeout(() => {
t = Date.now(), r(...a);
}, c - (o - t)));
}, cleanup: () => {
clearTimeout(u);
} };
}
function M(r, c, t, u) {
if (c.customFunction)
return {
rateLimitedFunc: c.customFunction(r, c.delay),
// eslint-disable-next-line @typescript-eslint/no-empty-function
cleanup: () => {
}
// Custom function should handle its own cleanup
};
const e = async (n, a) => {
t == null || t();
try {
await r(n, a);
} finally {
u == null || u();
}
};
switch (c.type) {
case "debounce": {
const { debouncedFunc: n, cleanup: a } = H(e, c.delay);
return { rateLimitedFunc: n, cleanup: a };
}
case "throttle": {
const { throttledFunc: n, cleanup: a } = K(e, c.delay);
return { rateLimitedFunc: n, cleanup: a };
}
default:
return {
rateLimitedFunc: e,
// eslint-disable-next-line @typescript-eslint/no-empty-function
cleanup: () => {
}
};
}
}
function R(r, c) {
const {
key: t,
initial: u,
persistor: e,
onError: n,
retryOnError: a = !0,
rateLimit: o
} = r, h = P(() => (t == null ? void 0 : t.toString()) || "", [t]), { cache: F } = x(), f = J(null), [L, S] = N(!1), b = w(() => !(e != null && e.onSet) || !o ? null : M(
async (l, s) => {
try {
await Promise.resolve(e.onSet(l, s));
} catch (d) {
if (n == null || n(d), !a)
throw d;
}
},
o,
() => S(!0),
() => S(!1)
), [e == null ? void 0 : e.onSet, o, n, a]), W = w(async () => {
var i, l;
try {
const s = (i = F.get(h)) == null ? void 0 : i.data;
return e != null && e.onGet ? s === void 0 ? await Promise.resolve(e.onGet(t)) ?? u : s : s ?? u;
} catch (s) {
if (n == null || n(s), a)
throw s;
return ((l = F.get(h)) == null ? void 0 : l.data) ?? u;
}
}, [F, h, e == null ? void 0 : e.onGet, t, u, n, a]), y = k(t, W, {
fallbackData: u,
revalidateOnFocus: !1,
revalidateOnReconnect: !1,
refreshWhenHidden: !1,
refreshWhenOffline: !1,
...c
}), { data: v, mutate: C, error: D, isLoading: O } = y, T = w(
(i, l) => {
const s = (G) => {
const p = G ?? v, m = typeof i == "function" ? i(p) : i;
return JSON.stringify(m) === JSON.stringify(p) ? p : (e != null && e.onSet && (f.current ? f.current.func(t, m) : Promise.resolve(e.onSet(t, m)).catch((I) => {
n == null || n(I);
})), m);
}, d = typeof l == "boolean" ? { revalidate: l } : l ? { ...l } : { revalidate: !1 };
C(s, d);
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[C, t, e == null ? void 0 : e.onSet, n]
), g = P(() => ({
...y,
isLoading: O,
error: D,
isPersisting: L
}), [y, O, D, L]);
return j(() => {
if (o && !f.current) {
const i = b();
i && (f.current = {
func: i.rateLimitedFunc,
cleanup: i.cleanup
});
}
return () => {
f.current && (f.current.cleanup(), f.current = null);
};
}, [b]), [
v,
T,
g
];
}
function q(r, c) {
return (t) => R({
...r,
initial: t ?? r.initial
}, c);
}
const B = {
createStore: q,
useStore: R
};
export {
q as createStore,
B as default,
R as useStore
};