react-singleton-hook
Version:
Share custom hook state across all components
87 lines (85 loc) • 3.42 kB
JavaScript
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
import React, { useState, useEffect, useRef } from 'react';
import { SingleItemContainer } from './SingleItemContainer';
import { mount } from '../utils/env';
import { warning } from '../utils/warning';
var nextKey = 1;
var automaticRender = false;
var manualRender = false;
var workingSet = [];
var renderedContainers = [];
var notifyContainersAsync = function notifyContainersAsync() {
renderedContainers.forEach(function (updateRenderedHooks) {
return updateRenderedHooks();
});
};
export var SingletonHooksContainer = function SingletonHooksContainer(_ref) {
var automaticContainerInternalUseOnly = _ref.automaticContainerInternalUseOnly;
var _useState = useState([]),
hooks = _useState[0],
setHooks = _useState[1];
var currentHooksRef = useRef();
currentHooksRef.current = hooks;
// if there was no automaticRender, and this one is not automatic as well
if (!automaticContainerInternalUseOnly && automaticRender === false) {
manualRender = true;
}
useEffect(function () {
var mounted = true;
function updateRenderedHooks() {
if (!mounted) return;
if (renderedContainers[0] !== updateRenderedHooks) {
if (!automaticContainerInternalUseOnly && automaticRender === true) {
warning('SingletonHooksContainer is mounted after some singleton hook has been used.' + 'Your SingletonHooksContainer will not be used in favor of internal one.');
}
setHooks(function (_) {
return [];
});
return;
}
setHooks([].concat(workingSet));
}
renderedContainers.push(updateRenderedHooks);
notifyContainersAsync();
return function () {
mounted = false;
if (currentHooksRef.current.length > 0) {
warning('SingletonHooksContainer is unmounted, but it has active singleton hooks. ' + 'They will be reevaluated once SingletonHooksContainer is mounted again');
}
renderedContainers.splice(renderedContainers.indexOf(updateRenderedHooks), 1);
notifyContainersAsync();
};
}, [automaticContainerInternalUseOnly]);
return /*#__PURE__*/React.createElement(React.Fragment, null, hooks.map(function (_ref2) {
var hook = _ref2.hook,
key = _ref2.key;
return /*#__PURE__*/React.createElement(SingleItemContainer, _extends({}, hook, {
key: key
}));
}));
};
export var addHook = function addHook(hook) {
var key = nextKey++;
workingSet.push({
hook: hook,
key: key
});
// no container and no previous manually rendered containers
if (renderedContainers.length === 0 && manualRender === false) {
automaticRender = true;
mount(SingletonHooksContainer);
}
notifyContainersAsync();
return function () {
workingSet.splice(workingSet.findIndex(function (h) {
return h.key === key;
}), 1);
notifyContainersAsync();
};
};
export var resetLocalStateForTests = function resetLocalStateForTests() {
automaticRender = false;
manualRender = false;
workingSet.splice(0, workingSet.length);
renderedContainers.splice(0, renderedContainers.length);
};