react-async-states-utils
Version:
utilities for react-async-states package
125 lines (122 loc) • 5.25 kB
JavaScript
import * as React from 'react';
import { useAsyncState, Status, useAsync } from 'react-async-states';
let emptyArray = [];
function isFunction(fn) {
return typeof fn === "function";
}
const StateBoundaryContext = React.createContext(null);
function StateBoundary(props) {
return React.createElement(StateBoundaryImpl, Object.assign({ key: props.strategy }, props), props.children);
}
var RenderStrategy;
(function (RenderStrategy) {
RenderStrategy[RenderStrategy["FetchAsYouRender"] = 0] = "FetchAsYouRender";
RenderStrategy[RenderStrategy["FetchThenRender"] = 1] = "FetchThenRender";
RenderStrategy[RenderStrategy["RenderThenFetch"] = 2] = "RenderThenFetch";
})(RenderStrategy || (RenderStrategy = {}));
let BoundarySourceContext = React.createContext(null);
function BoundarySource({ source, children, }) {
let parentSource = React.useContext(BoundarySourceContext);
let contextValue = React.useMemo(() => ({
source,
parent: parentSource,
}), [source, parentSource]);
return (React.createElement(BoundarySourceContext.Provider, { value: contextValue }, children));
}
function StateBoundaryImpl(props) {
if (props.strategy === RenderStrategy.FetchThenRender) {
return React.createElement(FetchThenRenderBoundary, props);
}
if (props.strategy === RenderStrategy.FetchAsYouRender) {
return React.createElement(FetchAsYouRenderBoundary, props);
}
return React.createElement(RenderThenFetchBoundary, props);
}
function inferBoundaryChildren(result, props) {
if (!props.render || !result.source) {
return props.children;
}
const { status } = result.source.getState();
return props.render[status] ? props.render[status] : props.children;
}
function renderChildren(children, props) {
return isFunction(children) ? React.createElement(children, props) : children;
}
function RenderThenFetchBoundary(props) {
let result = useAsyncState(props.config, props.dependencies);
const children = inferBoundaryChildren(result, props);
let Context = StateBoundaryContext;
return (React.createElement(BoundarySource, { source: result.source },
React.createElement(Context.Provider, { value: result }, renderChildren(children, result))));
}
function FetchAsYouRenderBoundary(props) {
let result = useAsyncState(props.config, props.dependencies);
result.read(); // throws
const children = inferBoundaryChildren(result, props);
let Context = StateBoundaryContext;
return (React.createElement(BoundarySource, { source: result.source },
React.createElement(Context.Provider, { value: result }, renderChildren(children, result))));
}
function FetchThenRenderInitialBoundary({ dependencies = emptyArray, result, config, }) {
result.source?.patchConfig({
skipPendingStatus: true,
});
React.useEffect(() => {
if (config.condition !== false) {
const autoRunArgs = config
.autoRunArgs;
if (Array.isArray(autoRunArgs)) {
return result.source.run.apply(null, autoRunArgs);
}
return result.source.run.apply(null);
}
}, dependencies);
return null;
}
function FetchThenRenderBoundary(props) {
let result = useAsyncState(props.config, props.dependencies);
let Context = StateBoundaryContext;
switch (result.source?.getState().status) {
case Status.pending:
case Status.initial: {
return (React.createElement(FetchThenRenderInitialBoundary, { result: result, config: props.config, dependencies: props.dependencies }));
}
case Status.error:
case Status.success: {
const children = inferBoundaryChildren(result, props);
return (React.createElement(BoundarySource, { source: result.source },
React.createElement(Context.Provider, { value: result }, renderChildren(children, result))));
}
}
return null;
}
function useCurrentState() {
const ctxValue = React.useContext(StateBoundaryContext);
if (ctxValue === null) {
throw new Error("useCurrentState used outside StateBoundary");
}
return ctxValue;
}
function recursivelyTraverseContextAndGetSource(ctxValue, stateKey) {
if (!stateKey) {
return ctxValue.source;
}
let currentSource = ctxValue.source;
if (currentSource.key === stateKey) {
return currentSource;
}
if (ctxValue.parent !== null) {
return recursivelyTraverseContextAndGetSource(ctxValue.parent, stateKey);
}
throw new Error(`(${stateKey}) was not found in boundary tree`);
}
function useBoundary(stateKey) {
const ctxValue = React.useContext(BoundarySourceContext);
if (ctxValue === null) {
throw new Error("useBoundary used outside StateBoundary");
}
let source = recursivelyTraverseContextAndGetSource(ctxValue, stateKey);
return useAsync(source);
}
export { FetchAsYouRenderBoundary, FetchThenRenderBoundary, RenderStrategy, RenderThenFetchBoundary, StateBoundary, useBoundary, useCurrentState };
//# sourceMappingURL=StateBoundary.js.map