#tanstack for server action mutation
1 messages · Page 1 of 1 (latest)
Your approach is not fully aligned with how Next.js Server Actions are intended to be used in the App Router (Next.js 13+ and 15). Here’s why:
Key Points from the Docs
- Server Actions are designed to be invoked directly from forms (using the
actionprop) or from client components via direct function calls, not through client-side libraries like TanStack Query (react-query) that expect to call API endpoints or client-side functions. Server Actions run on the server, and their invocation is handled by the Next.js framework, not by client-side fetches or mutations Server Actions and Mutations. - When you use a form with an
actionprop, Next.js will serialize the form data and invoke the server action on the server. You do not need to wrap this in a mutation hook; instead, you can use React’s built-in hooks likeuseActionStateoruseFormStatusto handle loading and error states Mutations with Server Actions. - If you want to call a server action from a client component (e.g., on a button click), you can import the server action and call it directly, as shown in the docs. You do not need to use TanStack Query for this Using Server Actions in Client Components.
What’s Wrong with Your Approach?
- You are importing a server action (
createContentSubmission) into a client component and passing it touseMutationfrom TanStack Query. This is not the intended usage, as TanStack Query expects to call an API endpoint, not a server action. - Server Actions are not regular async functions—they are special functions that Next.js serializes and invokes on the server. Wrapping them in
useMutationcan lead to unexpected behavior or errors, especially as the framework evolves.
Recommended Approach
- For form submissions: Use the
<form action={serverAction}>pattern. Handle loading and error states withuseActionStateoruseFormStatus. - For client-side triggers: Import the server action and call it directly in your client component’s event handler.
Example: Form Submission with Server Action
// app/lib/actions/submission.ts
'use server';
export async function createContentSubmission(formData: FormData) {
// ...validation and mutation logic
}
// In your component
export default function MyForm() {
return (
<form action={createContentSubmission}>
<input type="hidden" name="contentId" value={contentId} required />
<button type="submit">I understand, start now</button>
</form>
);
}
You can use useActionState to handle loading and error states if needed.
Example: Client Component Trigger
'use client'
import { createContentSubmission } from '@/lib/actions/submission'
function MyButton({ contentId }) {
const handleClick = async () => {
await createContentSubmission(contentId)
// handle navigation or state updates
}
return <button onClick={handleClick}>Start</button>
}
See more in the Server Actions and Mutations documentation.