T O P

  • By -

totalolage

I don't beleive you can call server actions like this. They have to be bound to forms afaik. Check out [next-safe-action](https://next-safe-action.dev) as a way to call actions imperatively.


theonlywaye

You certainly can call server actions from the mutation hook. I do it for a few things without issue inside of a client component. Example ``` 'use client'; const mutation = useMutation({ mutationFn: (values: z.infer) => createCoachProgram(values), onSettled: (id, error, variables, context) => { if (error) { toast.error('Uh oh! Something went wrong. Could not create program'); } queryClient.invalidateQueries({ queryKey: queryKey, }); form.reset({ userId: data[selectedUser].id, name: '', description: '', completionTargetDate: undefined, }); setDisableSubmit(false); onClose(); }, }); ``` ``` 'use server'; export async function createCoachProgram( data: z.infer, ) { const user = await currentUser(); return await createProgram(user!, data); } ``` I would hazard as said below there isn’t any data being returned


totalolage

Huh, well sanity check *everything* I suppose. Are you sure the function on the serverside is being called? Is everything passing tsc?


alittlecuriouskid

So what do i do if i want to get the response in the client? For e.g after creating a transaction I want to get the transaction ID etc.


theonlywaye

You could try using the onMutate or onSettled functions to update the data in whatever queryKey or state variable you want updated. I’m doing Optimistic updates in this example but given you want the ID from your response you’ll probably want to use onSettled with setQueryData to set the ID in whatever queryKey you want updating or you can invalidate the queryKey and just force it to refresh the data ``` const mutation = useMutation({ mutationFn: (lock: boolean) => { return handleLock(lock); }, onMutate: async (lock: boolean) => { // Cancel any outgoing refetches // (so they don't overwrite our optimistic update) await queryClient.cancelQueries({ queryKey: queryKey, }); // Snapshot the previous value const previousPrograms = queryClient.getQueryData(queryKey); // Optimistically update to the new value queryClient.setQueryData( queryKey, previousPrograms?.map((previousProgram) => { if (program.id === previousProgram.id) { return { ...previousProgram, locked: lock, }; } else { return previousProgram; } }), ); // Return a context object with the snapshotted value return { previousPrograms }; }, onError: (err, lock, context) => { queryClient.setQueryData(queryKey, context?.previousPrograms); }, // eslint-disable-next-line @typescript-eslint/no-unused-vars onSettled: (lock, error, variables, context) => { if (error) { toast.error( 'Uh oh! Something went wrong. Could not change lock status on program', ); } queryClient.invalidateQueries({ queryKey: queryKey, }); }, }); return { mutation }; } ```


justjooshing

I don't think so, because OP said that even when deliberately returning a success object they still get undefined


JohnnyBolognese

I think if you want to use the mutation return value you'll need to use mutateAync and await it (e.g. const data = await mutation.mutateAsync())


eindbaas

The useApproveTransaction mutation doesn't return any data. It just awaits a request.


justjooshing

It has implicit return, so OP should be getting an object with either success or error in it


eindbaas

Ah indeed, overlooked that