@dr.pogodin/react-global-state
Version:
Hook-based global state for React
97 lines (94 loc) • 3.74 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
exports.getGlobalState = getGlobalState;
exports.getSsrContext = getSsrContext;
var _lodash = require("lodash");
var _react = require("react");
var _GlobalState = _interopRequireDefault(require("./GlobalState"));
var _jsxRuntime = require("react/jsx-runtime");
const Context = /*#__PURE__*/(0, _react.createContext)(null);
/**
* Gets {@link GlobalState} instance from the context. In most cases
* you should use {@link useGlobalState}, and other hooks to interact with
* the global state, instead of accessing it directly.
* @return
*/
function getGlobalState() {
// TODO: Think about it: on one hand we on purpose called this function
// as getGlobalState(), so that ppl looking for the state hook prefer using
// useGlobalState(), while this getGlobalState() is reserved for nieche cases;
// on the other hand, perhaps we can rename it into useSomething, to both
// follow conventions, and to keep stuff clearly named at the same time.
// eslint-disable-next-line react-hooks/rules-of-hooks
const globalState = (0, _react.use)(Context);
if (!globalState) throw new Error('Missing GlobalStateProvider');
return globalState;
}
/**
* @category Hooks
* @desc Gets SSR context.
* @param throwWithoutSsrContext If `true` (default),
* this hook will throw if no SSR context is attached to the global state;
* set `false` to not throw in such case. In either case the hook will throw
* if the {@link <GlobalStateProvider>} (hence the state) is missing.
* @returns SSR context.
* @throws
* - If current component has no parent {@link <GlobalStateProvider>}
* in the rendered React tree.
* - If `throwWithoutSsrContext` is `true`, and there is no SSR context attached
* to the global state provided by {@link <GlobalStateProvider>}.
*/
function getSsrContext(throwWithoutSsrContext = true) {
const {
ssrContext
} = getGlobalState();
if (!ssrContext && throwWithoutSsrContext) {
throw new Error('No SSR context found');
}
return ssrContext;
}
/**
* Provides global state to its children.
* @param prop.children Component children, which will be provided with
* the global state, and rendered in place of the provider.
* @param prop.initialState Initial content of the global state.
* @param prop.ssrContext Server-side rendering (SSR) context.
* @param prop.stateProxy This option is useful for code
* splitting and SSR implementation:
* - If `true`, this provider instance will fetch and reuse the global state
* from a parent provider.
* - If `GlobalState` instance, it will be used by this provider.
* - If not given, a new `GlobalState` instance will be created and used.
*/
const GlobalStateProvider = ({
children,
...rest
}) => {
const localStateRef = (0, _react.useRef)(undefined);
let state;
// TODO: Revise.
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if ('stateProxy' in rest && rest.stateProxy) {
localStateRef.current = undefined;
state = rest.stateProxy === true ? getGlobalState() : rest.stateProxy;
} else {
if (!localStateRef.current) {
const {
initialState,
ssrContext
} = rest;
localStateRef.current = new _GlobalState.default((0, _lodash.isFunction)(initialState) ? initialState() : initialState, ssrContext);
}
state = localStateRef.current;
}
return /*#__PURE__*/(0, _jsxRuntime.jsx)(Context, {
value: state,
children: children
});
};
var _default = exports.default = GlobalStateProvider;
//# sourceMappingURL=GlobalStateProvider.js.map