Next.js Forms and Server Actions

Next.jsReact Server Components

Work in Progress

I've recently been working with Next.js and React Server Components, which provides a nice way to build fullstack web applications quickly

Key Concepts

Folder Structure

After some experimentation, I found some tricks with the folder structure to make it easier to work with, the main caveats I found are:

src/
└── components/
    └── forms/
        ├── login.ts
        └── login-action.tsx

I've found co-locating the form and action to be important, as they are tightly coupled (the form fields need to match the action's parameters).

Anatomy of a Form

login.tsx
"use client"; // Must be a client component, as it uses the useActionState hook
import { useActionState } from "react";
import action from "./login-action";
 
export function LoginForm() {
  const [state, submit, pending] = useActionState(loginAction, {
    success: false,
  });
 
  return (
    // Standard HTML form
    <form action={action}>
      <input type="text" name="username" />
      <input type="password" name="password" />
      <button type="submit" disabled={pending}>
        Login
      </button>
    </form>
  );
}

Anatomy of a Server Action

login-action.tsx
"use server"; // Must only run on the server
 
export interface FormState {
  success: boolean;
}
 
export default async function action(state: FormState, formData: FormData) {
  // Handle the form submission
  const username = formData.get("username");
  const password = formData.get("password");
 
  // Validate the input
  if (!username || !password) {
    return { success: false };
  }
 
  // Do something with the input (e.g. authenticate the user)
  const user = await authenticate(username, password);
 
  if (!user) {
    return { success: false };
  } else {
    return { success: true };
  }
}

Validation

Resources