Guides
Executing actions
There are four ways to execute a safe action from a Client Component. Each approach serves different needs:
Comparison
Given the same action:
"use server";
import { z } from "zod";
import { actionClient } from "@/lib/safe-action";
export const greetUser = actionClient
.inputSchema(z.object({ name: z.string() }))
.action(async ({ parsedInput }) => {
return { greeting: `Hello, ${parsedInput.name}!` };
});Here's how each method calls it:
"use client";
import { greetUser } from "./actions";
export default function Page() {
const handleClick = async () => {
const result = await greetUser({ name: "Alice" });
if (result.data) {
alert(result.data.greeting);
}
};
return <button onClick={handleClick}>Greet</button>;
}Use when: You need a simple one-off call, or you're calling from a Server Component or event handler where you don't need reactive UI updates.
Which method should I use?
| Need | Method |
|---|---|
| Simple call, no loading UI | Direct call |
| Loading states, callbacks, reactive result | useAction hook |
Forms with callbacks, status, and prevResult | useStateAction hook |
| Optimistic UI updates | useOptimisticAction hook |
| Progressive enhancement / no-JS forms | useActionState (React) |
| Server Component calling an action | Direct call |