UNPKG

next-safe-action

Version:

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

244 lines (240 loc) 6.12 kB
"use client"; import { t as FrameworkErrorHandler } from "./errors-BsNXg-5Q.mjs"; import { n as getActionStatus, r as useActionCallbacks, t as getActionShorthandStatusObject, } from "./hooks-utils-DA2xDVWH.mjs"; import * as React from "react"; //#region src/hooks.ts /** * Use the action from a Client Component via hook. * @param safeActionFn The action function * @param cb Optional base utils and callbacks * * {@link https://next-safe-action.dev/docs/execute-actions/hooks/useaction See docs for more information} */ const useAction = (safeActionFn, cb) => { const [isTransitioning, startTransition] = React.useTransition(); const [result, setResult] = React.useState({}); const [clientInput, setClientInput] = React.useState(); const [isExecuting, setIsExecuting] = React.useState(false); const [navigationError, setNavigationError] = React.useState(null); const [thrownError, setThrownError] = React.useState(null); const [isIdle, setIsIdle] = React.useState(true); const status = getActionStatus({ isExecuting, isTransitioning, result, isIdle, hasNavigated: navigationError !== null, hasThrownError: thrownError !== null, }); const execute = React.useCallback( (input) => { setTimeout(() => { setIsIdle(false); setNavigationError(null); setThrownError(null); setClientInput(input); setIsExecuting(true); }, 0); startTransition(() => { safeActionFn(input) .then((res) => setResult(res ?? {})) .catch((e) => { setResult({}); if (FrameworkErrorHandler.isNavigationError(e)) { setNavigationError(e); throw e; } setThrownError(e); throw e; }) .finally(() => { setIsExecuting(false); }); }); }, [safeActionFn] ); const executeAsync = React.useCallback( (input) => { return new Promise((resolve, reject) => { setTimeout(() => { setIsIdle(false); setNavigationError(null); setThrownError(null); setClientInput(input); setIsExecuting(true); }, 0); startTransition(() => { safeActionFn(input) .then((res) => { setResult(res ?? {}); resolve(res); }) .catch((e) => { setResult({}); if (FrameworkErrorHandler.isNavigationError(e)) { setNavigationError(e); throw e; } setThrownError(e); reject(e); }) .finally(() => { setIsExecuting(false); }); }); }); }, [safeActionFn] ); const reset = React.useCallback(() => { setIsIdle(true); setNavigationError(null); setThrownError(null); setClientInput(void 0); setResult({}); }, []); useActionCallbacks({ result: result ?? {}, input: clientInput, status, navigationError, thrownError, cb, }); return { execute, executeAsync, input: clientInput, result, reset, status, ...getActionShorthandStatusObject(status), }; }; /** * Use the action from a Client Component via hook, with optimistic data update. * @param safeActionFn The action function * @param utils Required `currentData` and `updateFn` and optional callbacks * * {@link https://next-safe-action.dev/docs/execute-actions/hooks/useoptimisticaction See docs for more information} */ const useOptimisticAction = (safeActionFn, utils) => { const [isTransitioning, startTransition] = React.useTransition(); const [result, setResult] = React.useState({}); const [clientInput, setClientInput] = React.useState(); const [isExecuting, setIsExecuting] = React.useState(false); const [navigationError, setNavigationError] = React.useState(null); const [thrownError, setThrownError] = React.useState(null); const [isIdle, setIsIdle] = React.useState(true); const [optimisticState, setOptimisticValue] = React.useOptimistic(utils.currentState, utils.updateFn); const status = getActionStatus({ isExecuting, isTransitioning, result, isIdle, hasNavigated: navigationError !== null, hasThrownError: thrownError !== null, }); const execute = React.useCallback( (input) => { setTimeout(() => { setIsIdle(false); setClientInput(input); setNavigationError(null); setThrownError(null); setIsExecuting(true); }, 0); startTransition(() => { setOptimisticValue(input); safeActionFn(input) .then((res) => setResult(res ?? {})) .catch((e) => { setResult({}); if (FrameworkErrorHandler.isNavigationError(e)) { setNavigationError(e); throw e; } setThrownError(e); throw e; }) .finally(() => { setIsExecuting(false); }); }); }, [safeActionFn, setOptimisticValue] ); const executeAsync = React.useCallback( (input) => { return new Promise((resolve, reject) => { setTimeout(() => { setIsIdle(false); setClientInput(input); setNavigationError(null); setThrownError(null); setIsExecuting(true); }, 0); startTransition(() => { setOptimisticValue(input); safeActionFn(input) .then((res) => { setResult(res ?? {}); resolve(res); }) .catch((e) => { setResult({}); if (FrameworkErrorHandler.isNavigationError(e)) { setNavigationError(e); throw e; } setThrownError(e); reject(e); }) .finally(() => { setIsExecuting(false); }); }); }); }, [safeActionFn, setOptimisticValue] ); const reset = React.useCallback(() => { setIsIdle(true); setClientInput(void 0); setNavigationError(null); setThrownError(null); setResult({}); }, []); useActionCallbacks({ result: result ?? {}, input: clientInput, status, navigationError, thrownError, cb: { onExecute: utils.onExecute, onSuccess: utils.onSuccess, onError: utils.onError, onSettled: utils.onSettled, onNavigation: utils.onNavigation, }, }); return { execute, executeAsync, input: clientInput, result, optimisticState, reset, status, ...getActionShorthandStatusObject(status), }; }; //#endregion export { useAction, useOptimisticAction }; //# sourceMappingURL=hooks.mjs.map