Valideringsfeil på feltnivå med useActionState
Returner strukturerte valideringsresultater fra actions, og vis innebygde feilmeldinger for hvert felt.
Valideringsfeil på feltnivå med useActionState er en gratis leksjon i Next.js 15 fullstack (App Router + Server Actions) på CoddyKit. Dette er leksjon 3 av 4. Du kan lese valgfritt 3 leksjoner fra denne læringsstien gratis i sin helhet – deretter låser CoddyKit PRO opp alle leksjoner, samt praktisk øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Den er en del av læringsløpet i Next.js 15 fullstack (App Router + Server Actions), og fremdriften din synkroniseres mellom nettet og CoddyKit-appen. Kurset i Next.js 15 fullstack (App Router + Server Actions) inneholder totalt 4 leksjoner.
Hvorfor feltnivåfeil?
Når et skjema ikke består valideringen, må brukerne vite nøyaktig hvilket felt som er feil, og hvorfor. Et enkelt banner med teksten "Noe gikk galt" tvinger dem til å gjette.
I Next.js 15 lar Server Actions sammen med useActionState Dem returnere et strukturert resultat fra serveren og gjengi en innebygd feilmelding rett under hvert inndatafelt.
emailer ugyldig → vis feilen under e-postfeltetpassworder for kort → vis den under passordfeltet
Denne leksjonen viser hvordan De returnerer denne strukturen og gjengir den på en ryddig måte.
Utforming av action-state
Begynn med å bestemme formen på det handlingen returnerer. Et godt mønster holder feil for hvert felt i et errors-kart med feltnavn som nøkler, der hver verdi er en rekke meldinger.
Ved å definere en TypeScript-type blir kontrakten tydelig både for handlingen og komponenten.
export type FieldErrors = {
email?: string[];
password?: string[];
};
export type SignupState = {
errors?: FieldErrors;
// value the user typed, so we can re-fill the form
values?: { email?: string };
// a top-level message for non-field errors
message?: string;
};
export const initialState: SignupState = {};Validering med Zod i handlingen
Et skjemabibliotek som Zod gir Dem både validering og en ferdig feilstruktur. Kall safeParse slik at feil ikke kaster et unntak – i stedet kan De undersøke resultatet.
flatten().fieldErrors returnerer nøyaktig formen { field: string[] } som vi utformet, slik at den kan kobles direkte til state-en vår.
import { z } from 'zod';
const SignupSchema = z.object({
email: z.string().email('Enter a valid email'),
password: z.string().min(8, 'At least 8 characters'),
});
const result = SignupSchema.safeParse({
email: 'not-an-email',
password: '123',
});
if (!result.success) {
// { email: ['Enter a valid email'], password: ['At least 8 characters'] }
console.log(result.error.flatten().fieldErrors);
}Signaturen til Server Action
En handling som brukes med useActionState, mottar to argumenter: forrige state og den innsendte FormData. Den må returnere neste state.
Merk filen eller funksjonen med 'use server'. Les verdier med formData.get(...), valider dem, og returner feil i stedet for å kaste et unntak.
'use server';
import { z } from 'zod';
import type { SignupState } from './state';
const SignupSchema = z.object({
email: z.string().email('Enter a valid email'),
password: z.string().min(8, 'At least 8 characters'),
});
export async function signup(
prevState: SignupState,
formData: FormData,
): Promise<SignupState> {
const email = String(formData.get('email') ?? '');
const password = String(formData.get('password') ?? '');
const parsed = SignupSchema.safeParse({ email, password });
if (!parsed.success) {
return {
errors: parsed.error.flatten().fieldErrors,
values: { email }, // keep email, never echo the password
};
}
// ...persist the user here...
return { message: 'Account created' };
}Koble til useActionState
I klientkomponenten kaller De useActionState(action, initialState). Den returnerer en tuppel:
state– den nyeste verdien handlingen returnerteformAction– send denne til skjemaetsaction-egenskapisPending– true mens handlingen kjører (svært nyttig for å deaktivere knappen)
Husk 'use client'-direktivet – hooks kjører bare i klientkomponenter.
'use client';
import { useActionState } from 'react';
import { signup } from './actions';
import { initialState } from './state';
export function SignupForm() {
const [state, formAction, isPending] = useActionState(
signup,
initialState,
);
return (
<form action={formAction}>
{/* inputs go here */}
<button disabled={isPending}>
{isPending ? 'Creating...' : 'Sign up'}
</button>
</form>
);
}Gjengi en innebygd feilmelding
For å vise en feltfeil leser De den fra state.errors?.fieldName. Siden hvert felt inneholder en strengmatrise, kan De gjengi den første meldingen (eller iterere over alle).
Bruk optional chaining slik at den aller første gjengivelsen – når errors er udefinert – ikke fører til en krasj.
<div>
<label htmlFor="email">Email</label>
<input
id="email"
name="email"
type="email"
defaultValue={state.values?.email}
/>
{state.errors?.email && (
<p className="error">{state.errors.email[0]}</p>
)}
</div>Tilgjengelighet: Koble feil til inndatafelter
Skjermlesere bør kunngjøre feilen og koble den til feltet. To attributter gjør det meste av arbeidet:
aria-invalid– sett tiltruenår feltet har en feilaria-describedby– pek på id-en til feilelementet
Gi feilelementet en stabil id og en høflig live-region, slik at oppdateringer leses opp.
<input
id="email"
name="email"
type="email"
defaultValue={state.values?.email}
aria-invalid={!!state.errors?.email}
aria-describedby="email-error"
/>
{state.errors?.email && (
<p id="email-error" className="error" aria-live="polite">
{state.errors.email[0]}
</p>
)}Bevare brukerens inndata
Siden skjemaet gjengis på nytt fra server-state, vil et ukontrollert inndatafelt miste det brukeren skrev inn. Returner de trygge verdiene fra handlingen, og gi dem tilbake med defaultValue.
Send aldri passord tilbake til klienten. Returner bare felt uten sensitive opplysninger, for eksempel e-post, slik at brukeren slipper å skrive inn alt på nytt etter en valideringsfeil.
// in the action, on failure:
return {
errors: parsed.error.flatten().fieldErrors,
values: { email }, // safe to round-trip
// password is intentionally omitted
};
// in the component:
<input name="email" defaultValue={state.values?.email} />
<input name="password" type="password" /> {/* always blank */}En ren valideringshjelper De kan teste
Valideringslogikk trenger ikke Next.js for å være korrekt. Trekk den ut i en ren funksjon som tar imot enkle verdier og returnerer det samme { field: string[] }-feilkartet. Den kan enkelt enhetstestes og kjøres i enhver dommer.
type FieldErrors = { email?: string[]; password?: string[] };
function validateSignup(email: string, password: string): FieldErrors {
const errors: FieldErrors = {};
const emailOk = /^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email);
if (!emailOk) errors.email = ['Enter a valid email'];
if (password.length < 8) errors.password = ['At least 8 characters'];
return errors;
}
const e1 = validateSignup('bad', '123');
console.log(e1); // { email: [...], password: [...] }
const e2 = validateSignup('a@b.co', 'longenough');
console.log(Object.keys(e2).length === 0); // true
console.log(JSON.stringify(validateSignup('x@y.com', 'short')));Flere feil per felt
Ett felt kan bryte flere regler samtidig (tomt, for kort, feil format). Siden hver oppføring er en matrise, kan De gjengi hver melding som et listepunkt.
Zod samler automatisk flere problemer per felt, så fieldErrors.password kan inneholde mer enn én streng.
{state.errors?.password && (
<ul className="error-list">
{state.errors.password.map((msg) => (
<li key={msg}>{msg}</li>
))}
</ul>
)}Feil på toppnivå kontra feltfeil
Ikke alle feil hører til et felt. En konflikt på grunn av en e-postadresse som allerede finnes i databasen, eller en generell serverfeil, er en skjemafeil.
Behold begge kanalene i state-en: errors for feil per felt og message for hele skjemaet. Gjengi meldingen på toppnivå over feltene, slik at den ikke overses.
// in the action, after a successful parse:
try {
await createUser(email, password);
} catch (err) {
if (isUniqueViolation(err)) {
return { errors: { email: ['Email already in use'] } };
}
return { message: 'Something went wrong. Please try again.' };
}
// in the component, above the fields:
{state.message && <p role="alert">{state.message}</p>}Kort kontroll
Test forståelsen Deres av handlingskontrakten som brukes av useActionState.
Oppsummering
De kan nå bygge validering på feltnivå med Server Actions og useActionState:
- Utform state-en med et
errors-kart av typen{ field: string[] }, samt valgfrievaluesog enmessagepå toppnivå. - Valider i handlingen med
safeParse, og returnerflatten().fieldErrors– returner, ikke kast. - Koble til hooken med
useActionState(action, initialState), og sendformActiontil skjemaet; brukisPendingfor knappen. - Gjengi innebygde feilmeldinger fra
state.errors?.field, medaria-invalidogaria-describedbyfor tilgjengelighet. - Bevar inndata via
defaultValue, men send aldri passord tilbake. - Skill mellom kanalene:
errorsper felt kontramessagefor hele skjemaet.
Lær deg TypeScript med en AI-veileder – gratis
Skriv og kjør ekte kode i nettleseren, få umiddelbar hjelp fra en AI-veileder som er tilgjengelig døgnet rundt, og fortsett der du slapp – på nettet eller i appen.
- Kurs
- 22
- Leksjoner
- 88
Ofte stilte spørsmål
Er leksjonen «Valideringsfeil på feltnivå med useActionState» gratis?
Ja – du kan lese valgfritt 3 av leksjonene i læringsstien Next.js 15 fullstack (App Router + Server Actions), inkludert «Valideringsfeil på feltnivå med useActionState», gratis i sin helhet her på nettet. Deretter låser CoddyKit PRO opp alle leksjoner, samt interaktiv øving med en innebygd kodeeditor og en AI-veileder som er tilgjengelig døgnet rundt. Kurset i Next.js 15 fullstack (App Router + Server Actions) inneholder totalt 4 leksjoner.
Hva lærer jeg i «Valideringsfeil på feltnivå med useActionState»?
Returner strukturerte valideringsresultater fra actions, og vis innebygde feilmeldinger for hvert felt. Du øver på Next.js 15 fullstack (App Router + Server Actions) med praktisk kode som du kjører direkte i nettleseren, mens en AI-veileder som er tilgjengelig døgnet rundt, svarer på spørsmålene dine mens du jobber deg gjennom leksjonen.
Trenger jeg erfaring for å begynne med Next.js 15 fullstack (App Router + Server Actions)?
Ingen tidligere erfaring er nødvendig. Next.js 15 fullstack (App Router + Server Actions) på CoddyKit er lagt opp for både nybegynnere og viderekomne, så De kan begynne her eller helt fra start og lære i Deres eget tempo. Dette er leksjon 3 av 4.
Hvor lang tid tar leksjonen «Valideringsfeil på feltnivå med useActionState»?
De fleste CoddyKit-leksjoner tar omtrent 5–10 minutter. Hver leksjon er kort og interaktiv, slik at De gjør jevne fremskritt og kan fortsette akkurat der De slapp – både på nettet og i appen.
Kan jeg skrive og kjøre kode i denne Next.js 15 fullstack (App Router + Server Actions)-leksjonen?
Ja. Alle Next.js 15 fullstack (App Router + Server Actions)-leksjoner har en innebygd kodeeditor, slik at De kan skrive og kjøre ekte kode direkte i nettleseren og få umiddelbar tilbakemelding fra AI – uten lokal konfigurering.
Alle leksjonene i dette kurset
- Progressiv forbedring med form-prop-en Action
- Ventende og lastende tilstander med useFormStatus
- Valideringsfeil på feltnivå med useActionState
- Umiddelbar tilbakemelding med useOptimistic