import * as React from "react"; import { useContext, useRef, useEffect, useState } from "react"; import { createContext } from "react"; import { MasterObject } from "./master-object"; type MapValueType = (value: T) => E; export function makeProvider(useHook: () => T) { const ctx = createContext({} as MasterObject); function Provider({ children }: any) { const hookResult = useHook(); const [hookMaster, setHookMaster] = useState( new MasterObject(hookResult) ); useEffect(() => { if (hookMaster) { hookMaster.updateValues(hookResult); } }, [hookResult]); return {children}; } function useProvider(mapValues?: MapValueType): T & E { const content = useContext(ctx); const [tick, setTick] = useState(0); const [subscription] = useState(content.createSubscription()); const cache = useRef(undefined as any); useEffect(() => { subscription.setHandler(() => { if (mapValues) { const newValues = mapValues(subscription.value); const cachedValues: any = cache.current; if (!cache.current) { cache.current = newValues; return; } for (let key in newValues) { if (newValues[key] !== cachedValues[key]) { setTick(tick + 1); cache.current = newValues; break; } } } else setTick(tick + 1); }); return () => subscription.destroy(); }, [tick]); return mapValues ? cache.current || mapValues(subscription.value) : subscription.value; } return { Provider, useProvider }; }