From ba3a00d1e2ea7148203e3fec39476d275e18258f Mon Sep 17 00:00:00 2001 From: Edoardo Ranghieri Date: Thu, 23 Nov 2023 13:44:36 +0100 Subject: [PATCH] refactor(hooks): don't use ref for `safeAction` input --- packages/next-safe-action/src/hook.ts | 60 +++++++++++++-------------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/packages/next-safe-action/src/hook.ts b/packages/next-safe-action/src/hook.ts index 6d0dd49a..b4ac310a 100644 --- a/packages/next-safe-action/src/hook.ts +++ b/packages/next-safe-action/src/hook.ts @@ -46,7 +46,7 @@ const useActionCallbacks = ( const onErrorRef = useRef(cb?.onError); const onSettledRef = useRef(cb?.onSettled); - // Execute the callback on success or error, if provided. + // Execute the callback when the action status changes. useEffect(() => { const onExecute = onExecuteRef.current; const onSuccess = onSuccessRef.current; @@ -76,7 +76,7 @@ const useActionCallbacks = ( /** * Use the action from a Client Component via hook. * @param safeAction The typesafe action. - * @param callbacks Optional callbacks executed when the action succeeds or fails. + * @param callbacks Optional callbacks executed based on the action status. * * {@link https://next-safe-action.dev/docs/usage-from-client/hooks/useaction See an example} */ @@ -85,33 +85,34 @@ export const useAction = ( callbacks?: HookCallbacks ) => { const [, startTransition] = useTransition(); - const executor = useRef(safeAction); const [result, setResult] = useState>(DEFAULT_RESULT); const [input, setInput] = useState>(); const [isExecuting, setIsExecuting] = useState(false); const status = getActionStatus(isExecuting, result); - const execute = useCallback((input: z.input) => { - setInput(input); - setIsExecuting(true); - - return startTransition(() => { - return executor - .current(input) - .then((res) => setResult(res ?? DEFAULT_RESULT)) - .catch((e) => { - if (isNextRedirectError(e) || isNextNotFoundError(e)) { - throw e; - } - - setResult({ fetchError: isError(e) ? e.message : "Something went wrong" }); - }) - .finally(() => { - setIsExecuting(false); - }); - }); - }, []); + const execute = useCallback( + (input: z.input) => { + setInput(input); + setIsExecuting(true); + + return startTransition(() => { + return safeAction(input) + .then((res) => setResult(res ?? DEFAULT_RESULT)) + .catch((e) => { + if (isNextRedirectError(e) || isNextNotFoundError(e)) { + throw e; + } + + setResult({ fetchError: isError(e) ? e.message : "Something went wrong" }); + }) + .finally(() => { + setIsExecuting(false); + }); + }); + }, + [safeAction] + ); const reset = useCallback(() => { setResult(DEFAULT_RESULT); @@ -133,7 +134,8 @@ export const useAction = ( * **NOTE: This hook uses an experimental React feature.** * @param safeAction The typesafe action. * @param initialOptimisticData Initial optimistic data. - * @param callbacks Optional callbacks executed when the action succeeds or fails. + * @param reducer Optimistic state reducer. + * @param callbacks Optional callbacks executed based on the action status. * * {@link https://next-safe-action.dev/docs/usage-from-client/hooks/useoptimisticaction See an example} */ @@ -146,16 +148,13 @@ export const useOptimisticAction = >(DEFAULT_RESULT); const [input, setInput] = useState>(); + const [isExecuting, setIsExecuting] = useState(false); const [optimisticData, setOptimisticState] = useOptimistic>( initialOptimisticData, reducer ); - const [isExecuting, setIsExecuting] = useState(false); - - const executor = useRef(safeAction); - const status = getActionStatus(isExecuting, result); const execute = useCallback( @@ -165,8 +164,7 @@ export const useOptimisticAction = { setOptimisticState(input); - return executor - .current(input) + return safeAction(input) .then((res) => setResult(res ?? DEFAULT_RESULT)) .catch((e) => { if (isNextRedirectError(e) || isNextNotFoundError(e)) { @@ -180,7 +178,7 @@ export const useOptimisticAction = {