Writing Data
Choose the right tool for changing data and keeping your views in sync.
Quick chooser
useNexusMutation
: For client-initiated API calls where you want full control over the lifecycle.useNexusAction
: A wrapper for Server Actions, ideal when a server round-trip is preferable.useNexusFormAction
: For ergonomic integration of Server Actions with an HTML<form>
.
Revalidation
- Client cache: Call
revalidateClientTags(['tag'])
to update data on the client. - Server cache (ISR): Call
await revalidateServerTags(['tag'])
to update server-rendered content.
1. Client-side Mutations
Use useNexusMutation
for standard client-side data changes.
"use client";
import { useNexusMutation, revalidateClientTags } from "next-nexus/client";
import { todosDefinition } from "@/definitions";
export function AddTodo() {
// Pass a factory: (variables) => NexusDefinition
const { mutate, isPending } = useNexusMutation(todosDefinition.create, {
onSuccess: () => {
// Revalidate lists tagged with "todos" on the client
revalidateClientTags(["todos"]);
},
});
return (
<button onClick={() => mutate({ title: "New" })} disabled={isPending}>
Add
</button>
);
}
2. Server Actions
Use useNexusAction
to wrap a Server Action, which is useful for logic that must run on the server.
"use client";
import { useNexusAction, revalidateClientTags } from "next-nexus/client";
import { revalidateServerTags } from "next-nexus"; // Note: this is a universal import
export function AddTodoButton() {
const { execute, isPending } = useNexusAction(
async (title: string) => {
"use server";
// Perform your write operation (e.g., call a DB)
// ...
await revalidateServerTags(["todos"]);
return { ok: true };
},
{
onSuccess: () => revalidateClientTags(["todos"]),
}
);
return (
<button onClick={() => execute("New Title")} disabled={isPending}>
Add Todo
</button>
);
}
3. Form Actions
Use useNexusFormAction
to bind a Server Action directly to a form.
"use client";
import { useNexusFormAction, revalidateClientTags } from "next-nexus/client";
import { revalidateServerTags } from "next-nexus"; // Note: this is a universal import
export default function Form() {
const { formAction, isPending } = useNexusFormAction(
async (formData: FormData) => {
"use server";
const title = String(formData.get("title") ?? "");
// Perform your write operation
// ...
await revalidateServerTags(["todos"]);
return { ok: true };
},
{
onSuccess: () => revalidateClientTags(["todos"]),
}
);
return (
<form action={formAction}>
<input name="title" />
<button type="submit" disabled={isPending}>
Add
</button>
</form>
);
}
Tips
- Prefer tag-based revalidation over manual cache writes (
nexusCache
). It’s more predictable and ensures data is refetched consistently across all components. - Call
revalidateClientTags
inonSuccess
andrevalidateServerTags
inside your Server Action to keep client and server data in sync. - For optimistic UI, use local component state. The subsequent revalidation will ensure consistency with the server state.
See also: useNexusMutation, useNexusAction, useNexusFormAction, Revalidation.
Last updated on