UNPKG

swr-global-state

Version:

Zero-setup & simple global state management for React Components

144 lines (143 loc) 3.81 kB
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 };