DEV Community

Alex Booker
Alex Booker

Posted on β€’ Edited on

4

Learn useActionState quickly with an example (Next.js 15)

When using a form, the useActionState manages state by automatically updating a state variable with the value returned from the server action. This is particularly helpful for rendering input field validation errors, as shown in the example below using Zod.

form.tsx:

"use client";

import { useActionState } from "react";
import { signUp } from "../actions";

export default function SignUp() {
  const [state, action] = useActionState(signUp, {});

  return (
    <form action={action}>
      <div>
        <label htmlFor="username">Username:</label>
        <input
          type="text"
          id="username"
          name="username"
          defaultValue={state.username}
          required
        />
        {state.errors?.username && (
          <p className="text-sm text-red-500">{state.errors.username}</p>
        )}
      </div>

      <div>
        <label htmlFor="password">Password:</label>
        <input
          type="password"
          id="password"
          name="password"
          defaultValue={state.password}
        />
        {state.errors?.password && (
          <p className="text-sm text-red-500">{state.errors.password}</p>
        )}
      </div>
      <input type="submit" value="Sign Up" />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

actions.ts:

"use server";

import { z } from "zod";

const SignUpSchema = z.object({
  username: z.string(),
  password: z
    .string()
    .min(8, { message: "Be at least 8 characters long" })
    .regex(/[a-zA-Z]/, { message: "Contain at least one letter." })
    .regex(/[0-9]/, { message: "Contain at least one number." })
    .regex(/[^a-zA-Z0-9]/, {
      message: "Contain at least one special character.",
    })
    .trim(),
});

export type SignUpActionState = {
  username?: string;
  password?: string;
  errors?: {
    username?: string[];
    password?: string[];
  };
};

export async function signUp(
  _prevState: SignUpActionState,
  form: FormData
): Promise<SignUpActionState> {
  const username = form.get("username") as string;
  const password = form.get("password") as string;

  const validatedFields = SignUpSchema.safeParse({
    username,
    password,
  });

  if (!validatedFields.success) {
    return {
      username,
      password,
      errors: validatedFields.error.flatten().fieldErrors,
    };
  }

  // process validated form inputs here

  return { username, password };
}
Enter fullscreen mode Exit fullscreen mode

useActionState also returns an isPending property (example) that indicates whether the server action's promise is still resolving.

Reference isPending to temporarily disable form elements, such as a submit button, to prevent users from clicking it multiple times in quick succession before the ongoing action has completed.

useActionState vs useFormAction and useFormStatus

If you’re familiar with useFormAction and useFormStatus, you’ll find useActionState quite similar.

Essentially, it combines the functionality of both hooks and is renamed to reflect that server actions aren't just for forms (you can also use useActionState with buttons and other elements.)

Keep in mind that useFormStatus is deprecated as of Next.js 15 and you should import useActionState moving forward.

Image of AssemblyAI tool

Transforming Interviews into Publishable Stories with AssemblyAI

Insightview is a modern web application that streamlines the interview workflow for journalists. By leveraging AssemblyAI's LeMUR and Universal-2 technology, it transforms raw interview recordings into structured, actionable content, dramatically reducing the time from recording to publication.

Key Features:
πŸŽ₯ Audio/video file upload with real-time preview
πŸ—£οΈ Advanced transcription with speaker identification
⭐ Automatic highlight extraction of key moments
✍️ AI-powered article draft generation
πŸ“€ Export interview's subtitles in VTT format

Read full post

Top comments (0)

AWS Security LIVE!

Tune in for AWS Security LIVE!

Join AWS Security LIVE! for expert insights and actionable tips to protect your organization and keep security teams prepared.

Learn More

πŸ‘‹ Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay