UNPKG

next-safe-action

Version:

Type safe and validated Server Actions in your Next.js project.

257 lines (253 loc) 6.43 kB
"use client"; // src/hooks.ts import * as React2 from "react"; // src/hooks-utils.ts import * as React from "react"; var getActionStatus = ({ isIdle, isExecuting, result }) => { if (isIdle) { return "idle"; } else if (isExecuting) { return "executing"; } else if ( typeof result.validationErrors !== "undefined" || typeof result.bindArgsValidationErrors !== "undefined" || typeof result.serverError !== "undefined" ) { return "hasErrored"; } else { return "hasSucceeded"; } }; var getActionShorthandStatusObject = ({ status, isTransitioning }) => { return { isIdle: status === "idle", isExecuting: status === "executing", isTransitioning, isPending: status === "executing" || isTransitioning, hasSucceeded: status === "hasSucceeded", hasErrored: status === "hasErrored", }; }; var useExecuteOnMount = (args) => { const mounted = React.useRef(false); React.useEffect(() => { const t = setTimeout(() => { if (args.executeOnMount && !mounted.current) { args.executeFn(args.executeOnMount.input); mounted.current = true; } }, args.executeOnMount?.delayMs ?? 0); return () => { clearTimeout(t); }; }, [args]); }; var useActionCallbacks = ({ result, input, status, cb }) => { const onExecuteRef = React.useRef(cb?.onExecute); const onSuccessRef = React.useRef(cb?.onSuccess); const onErrorRef = React.useRef(cb?.onError); const onSettledRef = React.useRef(cb?.onSettled); React.useEffect(() => { const onExecute = onExecuteRef.current; const onSuccess = onSuccessRef.current; const onError = onErrorRef.current; const onSettled = onSettledRef.current; const executeCallbacks = async () => { switch (status) { case "executing": await Promise.resolve(onExecute?.({ input })); break; case "hasSucceeded": await Promise.all([ Promise.resolve(onSuccess?.({ data: result?.data, input })), Promise.resolve(onSettled?.({ result, input })), ]); break; case "hasErrored": await Promise.all([ Promise.resolve(onError?.({ error: result, input })), Promise.resolve(onSettled?.({ result, input })), ]); break; } }; executeCallbacks().catch(console.error); }, [status, result, input]); }; // src/hooks.ts var useAction = (safeActionFn, utils) => { const [isTransitioning, startTransition] = React2.useTransition(); const [result, setResult] = React2.useState({}); const [clientInput, setClientInput] = React2.useState(); const [isExecuting, setIsExecuting] = React2.useState(false); const [isIdle, setIsIdle] = React2.useState(true); const status = getActionStatus({ isExecuting, result, isIdle }); const execute = React2.useCallback( (input) => { setTimeout(() => { setIsIdle(false); setClientInput(input); setIsExecuting(true); }, 0); startTransition(() => { safeActionFn(input) .then((res) => setResult(res ?? {})) .catch((e) => { setResult({}); throw e; }) .finally(() => { setIsExecuting(false); }); }); }, [safeActionFn] ); const executeAsync = React2.useCallback( (input) => { const fn = new Promise((resolve, reject) => { setTimeout(() => { setIsIdle(false); setClientInput(input); setIsExecuting(true); }, 0); startTransition(() => { safeActionFn(input) .then((res) => { setResult(res ?? {}); resolve(res); }) .catch((e) => { setResult({}); reject(e); }) .finally(() => { setIsExecuting(false); }); }); }); return fn; }, [safeActionFn] ); const reset = React2.useCallback(() => { setIsIdle(true); setClientInput(void 0); setResult({}); }, []); useExecuteOnMount({ executeOnMount: utils?.executeOnMount, executeFn: execute, }); useActionCallbacks({ result: result ?? {}, input: clientInput, status, cb: { onExecute: utils?.onExecute, onSuccess: utils?.onSuccess, onError: utils?.onError, onSettled: utils?.onSettled, }, }); return { execute, executeAsync, input: clientInput, result, reset, status, ...getActionShorthandStatusObject({ status, isTransitioning }), }; }; var useOptimisticAction = (safeActionFn, utils) => { const [isTransitioning, startTransition] = React2.useTransition(); const [result, setResult] = React2.useState({}); const [clientInput, setClientInput] = React2.useState(); const [isExecuting, setIsExecuting] = React2.useState(false); const [isIdle, setIsIdle] = React2.useState(true); const [optimisticState, setOptimisticValue] = React2.useOptimistic(utils.currentState, utils.updateFn); const status = getActionStatus({ isExecuting, result, isIdle }); const execute = React2.useCallback( (input) => { setTimeout(() => { setIsIdle(false); setClientInput(input); setIsExecuting(true); }, 0); startTransition(() => { setOptimisticValue(input); safeActionFn(input) .then((res) => setResult(res ?? {})) .catch((e) => { setResult({}); throw e; }) .finally(() => { setIsExecuting(false); }); }); }, [safeActionFn, setOptimisticValue] ); const executeAsync = React2.useCallback( (input) => { const fn = new Promise((resolve, reject) => { setTimeout(() => { setIsIdle(false); setClientInput(input); setIsExecuting(true); }, 0); startTransition(() => { setOptimisticValue(input); safeActionFn(input) .then((res) => { setResult(res ?? {}); resolve(res); }) .catch((e) => { setResult({}); reject(e); }) .finally(() => { setIsExecuting(false); }); }); }); return fn; }, [safeActionFn, setOptimisticValue] ); const reset = React2.useCallback(() => { setIsIdle(true); setClientInput(void 0); setResult({}); }, []); useExecuteOnMount({ executeOnMount: utils?.executeOnMount, executeFn: execute, }); useActionCallbacks({ result: result ?? {}, input: clientInput, status, cb: { onExecute: utils.onExecute, onSuccess: utils.onSuccess, onError: utils.onError, onSettled: utils.onSettled, }, }); return { execute, executeAsync, input: clientInput, result, optimisticState, reset, status, ...getActionShorthandStatusObject({ status, isTransitioning }), }; }; export { useAction, useOptimisticAction }; //# sourceMappingURL=hooks.mjs.map