[FEATURE] executeAsync
enisze opened this issue · comments
Are you using the latest version of this library?
- I verified that the issue exists in the latest next-safe-action release
Is there an existing issue for this?
- I have searched the existing issues and found nothing that matches
Suggest an idea
I would like to await my execute and get the result inline instead of using the callbacks. Like e.g. mutate
and mutateAsync
in react-query. Was this already thought about / why is this not possible?
I would like to do something like this:
const result = await executeAsync(input)
Additional context
No response
You can await the Server Action by directly calling it. If you want to await execute
from useAction
/useOptimisticAction
hooks this is currently not possible, due to a React limitation discussed in #72. This limitation will go away when useActionState
will land in Next.js.
Ah I see thank you @TheEdoRan so its because useTransition
is used under the hood and that currently cannot be awaited?
The thing is I would like to still keep the loading and error states of the useAction hook thats why I was asking. :)
so its because
useTransition
is used under the hood and that currently cannot be awaited?
Yes, exactly.
The thing is I would like to still keep the loading and error states of the useAction hook thats why I was asking.
Yeah, hopefully this will be fixed with useActionState
hook, unfortunately React APIs for Server Actions are still pretty unstable (and undocumented) at this time.
Hey, I also miss this feature, if someone wants to have the execute async, there is my custom hook to handle it:
import { useRef } from 'react';
import { SafeAction } from 'next-safe-action/.';
import { HookCallbacks, useAction } from 'next-safe-action/hooks';
import { Schema, z } from 'zod';
export const useSafeAction = <const S extends Schema, const Data>(
safeAction: SafeAction<S, Data>,
callbacks?: HookCallbacks<S, Data> | undefined,
) => {
const promiseResolveRef =
useRef<(values: Data | PromiseLike<Data>) => void>();
const promiseRejectRef = useRef<(reason?: any) => void>();
const action = useAction(safeAction, {
...callbacks,
onSettled: (result, input, reset) => {
if (result.data) {
promiseResolveRef.current?.(result.data);
} else {
const message =
result.fetchError || result.serverError || 'Unknown error';
promiseRejectRef.current?.(message);
}
promiseResolveRef.current = undefined;
promiseRejectRef.current = undefined;
callbacks?.onSettled?.(result, input, reset);
},
});
const execute = async (input: z.infer<S>) =>
new Promise<Data>((resolve, reject) => {
promiseResolveRef.current = resolve;
promiseRejectRef.current = reject;
action.execute(input);
});
return {
...action,
execute,
};
};
@kriziu awesome, that works! But be aware that Next.js recommends to use useTransition
or useOptimistic
for non-form elements, and form related hooks for forms. This will be hopefully solved by useActionState
once for all.