UNPKG

dreamstate

Version:

Store management library based on react context and observers

80 lines (77 loc) 3.48 kB
import { useContext, useMemo, useEffect } from 'react'; import { ScopeContext } from '../../scoping/ScopeContext.js'; import { useForceUpdate } from '../../utils/useForceUpdate.js'; /** * A hook used internally for observing and injecting data based on the current scope. * * This hook consumes the provided context manager classes (`sources`) and the initial state, * performing data injection and provisioning within the context of the current scope. It returns * the current state registry, which is used for data provisioning throughout the component tree. * * @param {Array<TAnyContextManagerConstructor>} sources - An array of context manager class references * that will be observed for state changes. * @param {TAnyObject | undefined} initialState - The initial state to be used for data provisioning * when the hook is first invoked. * @returns {Map<TAnyContextManagerConstructor, TAnyObject>} A map of context manager classes and their * corresponding current states, used for providing data to components. */ function useSourceObserving(sources, initialState) { var scope = useContext(ScopeContext); var forceUpdate = useForceUpdate(); /* * Warn if current observer is mounted out of scope in dev mode. */ { if (!scope) { console.error("[DS]", "Dreamstate providers should be used in a scope. Wrap your component tree with ScopeProvider"); } } /* * Use memo for first and single init of required components. * The point is to force registering before provider rendering for first init. * * Registering will work in the same way even if it is called multiple times. * Dependencies array is mostly used for HMR updates to force reloading on class reference changes. */ useMemo(function () { for (var it_1 = 0; it_1 < sources.length; it_1++) { scope.INTERNAL.registerManager(sources[it_1], initialState); } }, sources); /* * Mount current observers and trigger related lifecycle methods when needed. * Count references of providers to detect whether we start provisioning or ending it. * * ! Iteration order is related to actual tree mount-unmount order imitating. * ! Dependencies array is mostly used for HMR updates to force reloading on class reference changes. */ useEffect(function () { var isSomethingRegistered = false; for (var it_2 = sources.length - 1; it_2 >= 0; it_2--) { /* * If something is registered, memoize it and force update to sync useEffect and actual provision tree. */ var registered = scope.INTERNAL.registerManager(sources[it_2], initialState); scope.INTERNAL.addServiceObserver(sources[it_2], forceUpdate); /* * Should stick to 'false' until at least one result is 'true'. */ isSomethingRegistered = registered || isSomethingRegistered; } /* * Re-sync scope providers if something was registered. * Normally happens with HMR chunks exchange and caused problems that use react context without subscription. * Required to force render of subscribed components after HMR with newest fast-refresh plugins. */ if (isSomethingRegistered) { forceUpdate(); } return function () { for (var it_3 = 0; it_3 < sources.length; it_3++) { scope.INTERNAL.removeServiceObserver(sources[it_3], forceUpdate); } }; }, sources); return scope.INTERNAL.REGISTRY.CONTEXT_STATES_REGISTRY; } export { useSourceObserving };