Server Actions & Data Mutations

5 questions found

What is a server action in React and what problem does it solve?

Intermediate
A server action is a function that runs directly on the server but can be called from a component as if it were a normal function, letting a form submit data and update a database without needing to manually build a separate API endpoint or write client side fetch code.
// A server action, marked with 'use server'
async function createPost(formData) {
  'use server';
  await db.posts.create({ title: formData.get('title') });
}

function NewPostForm() {
  return (
    <form action={createPost}>
      <input name="title" />
      <button type="submit">Create Post</button>
    </form>
  );
}
Real-world example A blogging platform lets writers publish a new post by submitting a form directly to a server action, skipping the need to build and call a separate API route just to save the post to the database.

Common follow-ups: How does a server action differ from a traditional API route in terms of how you write it?;What security considerations apply when writing a server action?

Server Components;Forms: Controlled & Uncontrolled Components

How does the useFormStatus hook help show loading feedback while a server action is running?

Advanced
useFormStatus gives you access to information about the nearest parent form's current submission state, including a pending flag, letting you disable a submit button or show a loading spinner automatically while a server action is still processing, without manually tracking that state yourself.
import { useFormStatus } from 'react-dom';

function SubmitButton() {
  const { pending } = useFormStatus();
  return (
    <button type="submit" disabled={pending}>
      {pending ? 'Saving' : 'Save'}
    </button>
  );
}
Real-world example A comment form automatically disables its submit button and shows a saving message while a server action processes the new comment, using useFormStatus instead of manually managing a separate loading state.

Common follow-ups: Why must useFormStatus be called inside a component nested within the form, rather than the form component itself?;How does this compare to manually tracking a loading state with useState?

Forms: Controlled & Uncontrolled Components;Custom Hooks

How does the useFormState hook, sometimes called useActionState, let you show validation errors returned from a server action?

Advanced
This hook connects a form to a server action and also gives you access to the most recent result returned by that action, such as a validation error message, letting you display feedback to the user without manually managing that state separately.
import { useActionState } from 'react';

async function createPost(previousState, formData) {
  'use server';
  if (!formData.get('title')) return { error: 'Title is required' };
  await db.posts.create({ title: formData.get('title') });
  return { error: null };
}

function NewPostForm() {
  const [state, formAction] = useActionState(createPost, { error: null });
  return (
    <form action={formAction}>
      <input name="title" />
      {state.error && <p>{state.error}</p>}
      <button type="submit">Create Post</button>
    </form>
  );
}
Real-world example A signup form shows a clear error message returned directly from its server action when a username is already taken, without needing any separate client side validation state to track that message.

Common follow-ups: What is passed as the previous state argument the very first time the form is submitted?;How does this pattern compare to handling errors with a traditional client side fetch call?

Error Handling;Forms: Controlled & Uncontrolled Components

How would you refresh data shown on a page after a server action successfully changes something in the database?

Intermediate
Frameworks that support server actions, like Next.js, provide a function such as revalidatePath, which tells the framework that data for a specific page is now outdated and should be fetched fresh the next time it is requested, ensuring users see the updated information right away.
async function deletePost(id) {
  'use server';
  await db.posts.delete(id);
  revalidatePath('/posts');
}
Real-world example A blog admin panel automatically shows an updated post list immediately after deleting a post, since the server action tells the framework to refresh the posts page's data right after the deletion completes.

Common follow-ups: What is the difference between revalidating a specific path and revalidating a specific data tag?;What happens if you forget to trigger revalidation after a mutation?

Server-Side Rendering (SSR) & Next.js;Data Fetching (React Query & SWR)

What is a simple real world example of using a server action for a common form, like a newsletter signup?

Beginner
A newsletter signup form can call a server action directly when submitted, which saves the visitor's email address to a database on the server, without the developer needing to write a separate API route or manual fetch call just for this one simple task.
async function subscribeToNewsletter(formData) {
  'use server';
  const email = formData.get('email');
  await db.subscribers.create({ email });
}

<form action={subscribeToNewsletter}>
  <input name="email" type="email" placeholder="Enter your email" />
  <button type="submit">Subscribe</button>
</form>
Real-world example A company blog adds a simple newsletter signup form at the bottom of every article, saving each new subscriber's email directly through a server action without building any extra backend code just for this feature.

Common follow-ups: How would you show a thank you message after the visitor successfully subscribes?;What validation should be added to prevent invalid or duplicate email addresses?

Forms: Controlled & Uncontrolled Components;Email & Notifications