UNPKG

react-async-states-utils

Version:
125 lines (122 loc) 5.25 kB
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