dreamstate
Version:
Store management library based on react context and observers
80 lines (77 loc) • 3.48 kB
JavaScript
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 };