react-singleton-hook
Version:
Share custom hook state across all components
60 lines (59 loc) • 1.86 kB
JavaScript
import { useEffect, useState } from 'react';
import { addHook } from './components/SingletonHooksContainer';
import { batch } from './utils/env';
export var singletonHook = function singletonHook(initValue, useHookBody, options) {
if (options === void 0) {
options = {};
}
var mounted = false;
var removeHook = undefined;
var initStateCalculated = false;
var lastKnownState = undefined;
var consumers = [];
var _options = options,
_options$unmountIfNoC = _options.unmountIfNoConsumers,
unmountIfNoConsumers = _options$unmountIfNoC === void 0 ? false : _options$unmountIfNoC;
var applyStateChange = function applyStateChange(newState) {
lastKnownState = newState;
batch(function () {
return consumers.forEach(function (c) {
return c(newState);
});
});
};
var stateInitializer = function stateInitializer() {
if (!initStateCalculated) {
lastKnownState = typeof initValue === 'function' ? initValue() : initValue;
initStateCalculated = true;
}
return lastKnownState;
};
return function () {
var _useState = useState(stateInitializer),
state = _useState[0],
setState = _useState[1];
useEffect(function () {
if (!mounted) {
mounted = true;
removeHook = addHook({
initValue: initValue,
useHookBody: useHookBody,
applyStateChange: applyStateChange
});
}
consumers.push(setState);
if (lastKnownState !== state) {
setState(lastKnownState);
}
return function () {
consumers.splice(consumers.indexOf(setState), 1);
if (consumers.length === 0 && unmountIfNoConsumers) {
removeHook();
mounted = false;
}
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
return state;
};
};