Deviopath › Next.js

Validated Server Action for useActionState

Hard · Server Actions

With React's useActionState(action, initialState), a form calls a Server Action as action(previousState, formData) and renders whatever state it returns: field errors, the values to put back in the inputs, or a success message. FormData only contains strings, so the action has to convert and validate them itself.

Implement the Server Action signup(prevState, formData) using SIGNUP_SCHEMA from the starter. Check the rules of each field in this order and keep only the first error per field:

- text / email: the value is formData.get(name) trimmed ("" when missing). Empty and required: "Required". Shorter than minLength: "Must be at least N characters". For email, not matching EMAIL_RE: "Enter a valid email".

- password: same, but never trimmed.

- number: the trimmed string. Empty is fine unless required. Not matching /^-?\d+$/: "Must be a whole number". Below min: "Must be at least N". Above max: "Must be at most N".

- checkbox: true only when the value is exactly "on" (what a checked box sends), otherwise false.

- multi: all values from formData.getAll(name). The first value that is not in options: "Unknown option: <value>". More than max values: "Choose at most N".

Every returned state has attempts = (prevState?.attempts ?? 0) + 1.

- If there are errors, return { status: "error", attempts, fieldErrors, values }. fieldErrors holds only the failing fields. values refills the form: trimmed name and email, age as the trimmed string, newsletter as a boolean, interests as an array. Never send the password back.

- Otherwise return { status: "success", attempts, message: "Welcome, <name>!" } with the trimmed name.

The driver runForm(submissions) is already written: each submission is a list of [key, value] pairs appended to a new FormData.

Next: Login Flow with Redirects