import { useEffect, useRef, useState } from "react"; export const useLocal = ( data: T, effect?: (arg: { init: boolean; }) => Promise void)> | void | (() => void), deps?: any[] ): { [K in keyof T]: T[K] extends Promise ? null | Awaited : T[K]; } & { render: (force?: boolean) => void } => { const [, _render] = useState({}); const _ = useRef({ data: data as unknown as T & { render: (force?: boolean) => void; }, deps: (deps || []) as any[], promisedKeys: new Set(), ready: false, _loading: {} as any, }); const local = _.current; useEffect(() => { local.ready = true; if (effect) effect({ init: true }); }, []); if (local.ready === false) { local._loading = {}; for (const [k, v] of Object.entries(data)) { if (!local.promisedKeys.has(k)) { let val = v; if (typeof val === "object" && val instanceof Promise) { local._loading[k] = true; local.promisedKeys.add(k); (local.data as any)[k] = null; val.then((resolved) => { (local.data as any)[k] = resolved; local._loading[k] = false; local.data.render(); }); } } } local.data.render = (force) => { if (force) _render({}) else if (local.ready) _render({}); }; } else { if (local.deps.length > 0 && deps) { for (const [k, dep] of Object.entries(deps) as any) { if (local.deps[k] !== dep) { local.deps[k] = dep; if (effect) { setTimeout(() => { effect({ init: false }); }); } break; } } } } return local.data as any; };