Skip to content

Latest commit

 

History

History
124 lines (91 loc) · 2.42 KB

File metadata and controls

124 lines (91 loc) · 2.42 KB

Server Actions for Form Handling

Next.js Server Actions

Server Actions let you run server code directly from forms without API routes.

Server Actions

Basic Server Action

// app/actions.ts
'use server';

export async function createPost(formData: FormData) {
  const title = formData.get('title') as string;
  const content = formData.get('content') as string;

  await db.post.create({
    data: { title, content }
  });

  revalidatePath('/posts');
}

Using in a Form

// app/new-post/page.tsx
import { createPost } from './actions';

export default function NewPostPage() {
  return (
    <form action={createPost}>
      <input name="title" placeholder="Title" required />
      <textarea name="content" placeholder="Content" required />
      <button type="submit">Create Post</button>
    </form>
  );
}

With Validation & Error Handling

'use server';

import { z } from 'zod';

const schema = z.object({
  email: z.string().email(),
  password: z.string().min(8),
});

export async function signup(formData: FormData) {
  const result = schema.safeParse({
    email: formData.get('email'),
    password: formData.get('password'),
  });

  if (!result.success) {
    return { error: result.error.flatten() };
  }

  // Create user...
  return { success: true };
}

Pending State with useFormStatus

'use client';

import { useFormStatus } from 'react-dom';

function SubmitButton() {
  const { pending } = useFormStatus();

  return (
    <button disabled={pending}>
      {pending ? 'Submitting...' : 'Submit'}
    </button>
  );
}

Optimistic Updates

'use client';

import { useOptimistic } from 'react';

function TodoList({ todos, addTodo }) {
  const [optimisticTodos, addOptimisticTodo] = useOptimistic(
    todos,
    (state, newTodo) => [...state, newTodo]
  );

  async function handleSubmit(formData) {
    const title = formData.get('title');
    addOptimisticTodo({ title, pending: true });
    await addTodo(formData);
  }

  return (
    <form action={handleSubmit}>
      {/* ... */}
    </form>
  );
}

Learned: December 20, 2025 Tags: Next.js, Server Actions, Forms