UNPKG

atomico

Version:

Atomico is a small library for the creation of interfaces based on web-components, only using functions and hooks.

67 lines (59 loc) 2 kB
import { useContext } from "../../context.js"; import { useId } from "../create-hooks.js"; import { useEffect, useLayoutEffect, useState } from "../hooks.js"; import { SuspenseContext, SuspenseEvent } from "./use-suspense.js"; /** * @type {import("core").UsePromise} */ export const usePromise = (callback, args, autorun = true) => { const id = useId(); const { dispatch } = useContext(SuspenseContext); /** * @type {import("core").ReturnUseState<import("core").ReturnPromise<any>>} */ const [state, setState] = useState(autorun ? { pending: autorun } : {}); /** * @type {any[]} */ const currentArgs = args || []; useEffect(() => { if (autorun) { let cancel; setState(state.pending ? state : { pending: true }); callback(...currentArgs).then( (result) => { !cancel && setState({ result, fulfilled: true }); }, (result) => { !cancel && setState( result?.name === "AbortError" ? { result, aborted: true } : { result, rejected: true } ); } ); return () => (cancel = true); } else { setState((state) => (Object.keys(state).length ? {} : state)); } }, [autorun, ...currentArgs]); useLayoutEffect(() => { if (state.pending) { dispatch(SuspenseEvent.pending, id); } else if (state.rejected) { dispatch(SuspenseEvent.rejected, id); } else if (state.aborted) { dispatch(SuspenseEvent.aborted, id); } else { dispatch(SuspenseEvent.fulfilled, id); } }, [dispatch, state]); useEffect( () => () => { dispatch(SuspenseEvent.fulfilled, id); }, [dispatch] ); return state; };