React + Next.js

Forms, Server Actions, Auth and State

35 min

Server actions

Next.js lets forms call server functions directly:

// app/contact/page.jsx
import { z } from "zod";
import { redirect } from "next/navigation";

const Contact = z.object({
  name: z.string().min(1).max(100),
  email: z.string().email(),
  message: z.string().min(20).max(2000),
});

async function sendMessage(formData) {
  "use server";
  const parsed = Contact.safeParse(Object.fromEntries(formData));
  if (!parsed.success) {
    return { errors: parsed.error.flatten().fieldErrors };
  }
  await saveLead(parsed.data);
  redirect("/contact/thanks");
}

export default function ContactPage() {
  return (
    <form action={sendMessage}>
      <input name="name" required />
      <input name="email" type="email" required />
      <textarea name="message" required />
      <button>Send</button>
    </form>
  );
}

Server actions are public endpoints under the hood: validate inputs and check authorisation inside every action, exactly as you would in an API route.

Authentication

Common options:

  • Auth.js (NextAuth): OAuth providers (GitHub, Google) and email links.
  • Hosted services (Clerk, Supabase Auth): fast to integrate, with UI components.
  • Your own backend (for example a Flask API) issuing secure, HttpOnly session cookies.

Whatever you choose, protect pages on the server (middleware or checks in server components), not only by hiding links in the UI.

Global state

Most state should stay local or come from the server. For genuinely shared client state (a cart, UI preferences):

  • Context for rarely changing values (theme, current user).
  • Zustand for simple shared stores:
import { create } from "zustand";
export const useCart = create(set => ({
  items: [],
  add: item => set(s => ({ items: [...s.items, item] })),
  clear: () => set({ items: [] }),
}));

Styling

Next.js works with CSS Modules (styles.module.css, scoped automatically), Tailwind CSS, or global stylesheets. Pick one approach per project.

Exercise

Build a contact page with a server action, Zod validation, field error messages and a thank-you redirect; then add a cart store with Zustand that persists to localStorage.

Check yourself

  • Why must server actions validate input and check permissions?
  • Where should page protection happen?
  • When is Context better than a store library?

Seu progresso fica salvo apenas neste navegador.

Enviar para revisão (10 pontos)