Een uitgebreide gids voor Next.js 14 Server Actions, met best practices voor formulierafhandeling, gegevensvalidatie, beveiliging en geavanceerde technieken.
Next.js 14 Server Actions: Formulierafhandeling Best Practices Beheersen
Next.js 14 introduceert krachtige functies voor het bouwen van performante en gebruiksvriendelijke webapplicaties. Van deze functies vallen Server Actions op als een transformerende manier om formulierinzendingen en gegevensmutaties direct op de server af te handelen. Deze gids biedt een uitgebreid overzicht van Server Actions in Next.js 14, gericht op best practices voor formulierafhandeling, gegevensvalidatie, beveiliging en geavanceerde technieken. We verkennen praktische voorbeelden en bieden bruikbare inzichten om u te helpen robuuste en schaalbare webapplicaties te bouwen.
Wat zijn Next.js Server Actions?
Server Actions zijn asynchrone functies die op de server worden uitgevoerd en rechtstreeks vanuit React-componenten kunnen worden aangeroepen. Ze elimineren de noodzaak voor traditionele API-routes voor het afhandelen van formulierinzendingen en gegevensmutaties, wat resulteert in vereenvoudigde code, verbeterde beveiliging en verbeterde prestaties. Server Actions zijn React Server Components (RSC's), wat betekent dat ze op de server worden uitgevoerd, wat leidt tot snellere initiële paginaladingen en verbeterde SEO.
Belangrijkste voordelen van Server Actions:
- Vereenvoudigde Code: Verminder boilerplate code door de noodzaak voor aparte API-routes te elimineren.
- Verbeterde Beveiliging: Server-side uitvoering minimaliseert client-side kwetsbaarheden.
- Verbeterde Prestaties: Voer gegevensmutaties direct op de server uit voor snellere reactietijden.
- Geoptimaliseerde SEO: Maak gebruik van server-side rendering voor betere indexering door zoekmachines.
- Typeveiligheid: Profiteer van end-to-end typeveiligheid met TypeScript.
Uw Next.js 14 Project Instellen
Zorg ervoor dat u een Next.js 14-project hebt ingesteld voordat u zich verdiept in Server Actions. Als u helemaal opnieuw begint, maakt u een nieuw project aan met het volgende commando:
npx create-next-app@latest mijn-next-app
Zorg ervoor dat uw project de app
directorystructuur gebruikt om optimaal te profiteren van Server Components en Actions.
Basis Formulierafhandeling met Server Actions
Laten we beginnen met een eenvoudig voorbeeld: een formulier dat gegevens verzendt om een nieuw item in een database aan te maken. We gebruiken een eenvoudig formulier met een invoerveld en een verzendknop.
Voorbeeld: Een Nieuw Item Aanmaken
Definieer eerst een Server Action-functie binnen uw React-component. Deze functie behandelt de logica van de formulierinzending op de server.
// app/components/CreateItemForm.tsx
'use client';
import { useState } from 'react';
async function createItem(formData: FormData) {
'use server'
const name = formData.get('name') as string;
// Simuleer database interactie
console.log('Item aanmaken:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simuleer latentie
console.log('Item succesvol aangemaakt!');
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
await createItem(formData);
setIsSubmitting(false);
}
return (
);
}
Uitleg:
- De directive
'use client'
geeft aan dat dit een client-component is. - De functie
createItem
is gemarkeerd met de directive'use server'
, wat aangeeft dat het een Server Action is. - De functie
handleSubmit
is een client-side functie die de server action aanroept. Het behandelt ook de UI-status, zoals het uitschakelen van de knop tijdens het indienen. - Het
action
attribuut van het<form>
element is ingesteld op de functiehandleSubmit
. - De methode
formData.get('name')
haalt de waarde op van het 'name' invoerveld. - De
await new Promise
simuleert een databasebewerking en voegt latentie toe.
Gegevensvalidatie
Gegevensvalidatie is cruciaal voor het waarborgen van gegevensintegriteit en het voorkomen van beveiligingskwetsbaarheden. Server Actions bieden een uitstekende gelegenheid om server-side validatie uit te voeren. Deze aanpak helpt bij het beperken van risico's die gepaard gaan met alleen client-side validatie.
Voorbeeld: Invoergegevens Valideren
Pas de createItem
Server Action aan om validatielogica op te nemen.
// app/components/CreateItemForm.tsx
'use client';
import { useState } from 'react';
async function createItem(formData: FormData) {
'use server'
const name = formData.get('name') as string;
if (!name || name.length < 3) {
throw new Error('Item naam moet minimaal 3 tekens lang zijn.');
}
// Simuleer database interactie
console.log('Item aanmaken:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simuleer latentie
console.log('Item succesvol aangemaakt!');
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
try {
await createItem(formData);
} catch (error: any) {
setErrorMessage(error.message || 'Er is een fout opgetreden.');
} finally {
setIsSubmitting(false);
}
}
return (
{errorMessage && <p style={{ color: 'red' }}>{errorMessage}</p>}
);
}
Uitleg:
- De functie
createItem
controleert nu of dename
geldig is (minimaal 3 tekens lang). - Als de validatie mislukt, wordt er een fout gegenereerd.
- De functie
handleSubmit
is bijgewerkt om eventuele fouten die door de Server Action worden gegenereerd op te vangen en een foutmelding aan de gebruiker weer te geven.
Validatiebibliotheken Gebruiken
Overweeg voor complexere validatiescenario's validatiebibliotheken zoals:
- Zod: Een TypeScript-first bibliotheek voor schema-declaratie en validatie.
- Yup: Een JavaScript schema-bouwer voor het parsen, valideren en transformeren van waarden.
Hier is een voorbeeld met Zod:
// app/utils/validation.ts
import { z } from 'zod';
export const CreateItemSchema = z.object({
name: z.string().min(3, 'Item naam moet minimaal 3 tekens lang zijn.'),
});
// app/components/CreateItemForm.tsx
'use client';
import { useState } from 'react';
import { CreateItemSchema } from '../utils/validation';
async function createItem(formData: FormData) {
'use server'
const name = formData.get('name') as string;
const validatedFields = CreateItemSchema.safeParse({ name });
if (!validatedFields.success) {
return { errors: validatedFields.error.flatten().fieldErrors };
}
// Simuleer database interactie
console.log('Item aanmaken:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simuleer latentie
console.log('Item succesvol aangemaakt!');
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
try {
await createItem(formData);
} catch (error: any) {
setErrorMessage(error.message || 'Er is een fout opgetreden.');
} finally {
setIsSubmitting(false);
}
}
return (
{errorMessage && <p style={{ color: 'red' }}>{errorMessage}</p>}
);
}
Uitleg:
- Het
CreateItemSchema
definieert de validatieregels voor hetname
veld met Zod. - De methode
safeParse
probeert de invoergegevens te valideren. Als de validatie mislukt, retourneert het een object met de fouten. - Het
errors
object bevat gedetailleerde informatie over de validatiefouten.
Beveiligingsoverwegingen
Server Actions verbeteren de beveiliging door code op de server uit te voeren, maar het is nog steeds cruciaal om beveiligingsbest practices te volgen om uw applicatie te beschermen tegen veelvoorkomende bedreigingen.
Cross-Site Request Forgery (CSRF) Voorkomen
CSRF-aanvallen maken misbruik van het vertrouwen dat een website heeft in de browser van een gebruiker. Implementeer CSRF-beschermingsmechanismen om CSRF-aanvallen te voorkomen.
Next.js handelt automatisch CSRF-bescherming af bij het gebruik van Server Actions. Het framework genereert en valideert een CSRF-token voor elke formulierinzending, zodat de aanvraag afkomstig is van uw applicatie.
Gebruikersauthenticatie en Autorisatie Afhandelen
Zorg ervoor dat alleen geautoriseerde gebruikers bepaalde acties kunnen uitvoeren. Implementeer authenticatie- en autorisatiemechanismen om gevoelige gegevens en functionaliteit te beschermen.
Hier is een voorbeeld met NextAuth.js om een Server Action te beveiligen:
// app/components/CreateItemForm.tsx
'use client';
import { useState } from 'react';
import { getServerSession } from 'next-auth';
import { authOptions } from '../../app/api/auth/[...nextauth]/route';
async function createItem(formData: FormData) {
'use server'
const session = await getServerSession(authOptions);
if (!session) {
throw new Error('Niet geautoriseerd');
}
const name = formData.get('name') as string;
// Simuleer database interactie
console.log('Item aanmaken:', name, 'door gebruiker:', session.user?.email);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simuleer latentie
console.log('Item succesvol aangemaakt!');
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
try {
await createItem(formData);
} catch (error: any) {
setErrorMessage(error.message || 'Er is een fout opgetreden.');
} finally {
setIsSubmitting(false);
}
}
return (
{errorMessage && <p style={{ color: 'red' }}>{errorMessage}</p>}
);
}
Uitleg:
- De functie
getServerSession
haalt de sessie-informatie van de gebruiker op. - Als de gebruiker niet is geauthenticeerd (geen sessie), wordt een fout gegenereerd, waardoor de Server Action niet kan worden uitgevoerd.
Invoergegevens Sanitizen
Sanitize invoergegevens om Cross-Site Scripting (XSS)-aanvallen te voorkomen. XSS-aanvallen vinden plaats wanneer kwaadaardige code in een website wordt geïnjecteerd, wat potentieel gebruikersgegevens of applicatiefuncties in gevaar brengt.
Gebruik bibliotheken zoals DOMPurify
of sanitize-html
om door de gebruiker verstrekte invoer te sanitizen voordat u deze verwerkt in uw Server Actions.
Geavanceerde Technieken
Nu we de basis hebben behandeld, laten we enkele geavanceerde technieken voor het effectief gebruiken van Server Actions verkennen.
Optimistische Updates
Optimistische updates bieden een betere gebruikerservaring door de UI onmiddellijk bij te werken alsof de actie zal slagen, zelfs voordat de server dit bevestigt. Als de actie op de server mislukt, wordt de UI teruggezet naar de vorige status.
// app/components/UpdateItemForm.tsx
'use client';
import { useState } from 'react';
async function updateItem(id: string, formData: FormData) {
'use server'
const name = formData.get('name') as string;
// Simuleer database interactie
console.log('Item bijwerken:', id, 'met naam:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simuleer latentie
// Simuleer falen (voor demonstratiedoeleinden)
const shouldFail = Math.random() < 0.5;
if (shouldFail) {
throw new Error('Item bijwerken mislukt.');
}
console.log('Item succesvol bijgewerkt!');
return { name }; // Retourneer de bijgewerkte naam
}
export default function UpdateItemForm({ id, initialName }: { id: string; initialName: string }) {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
const [itemName, setItemName] = useState(initialName);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
// Optimistisch de UI bijwerken
const newName = formData.get('name') as string;
setItemName(newName);
try {
const result = await updateItem(id, formData);
//Bij succes is de update al zichtbaar in de UI via setItemName
} catch (error: any) {
setErrorMessage(error.message || 'Er is een fout opgetreden.');
// Zet de UI terug bij een fout
setItemName(initialName);
} finally {
setIsSubmitting(false);
}
}
return (
Huidige Naam: {itemName}
{errorMessage && <p style={{ color: 'red' }}>{errorMessage}</p>}
);
}
Uitleg:
- Voordat de Server Action wordt aangeroepen, wordt de UI onmiddellijk bijgewerkt met de nieuwe itemnaam met behulp van
setItemName
. - Als de Server Action mislukt, wordt de UI teruggezet naar de oorspronkelijke itemnaam.
Gegevens Herwalideren
Nadat een Server Action gegevens heeft gewijzigd, moet u mogelijk gecachte gegevens herwalideren om ervoor te zorgen dat de UI de nieuwste wijzigingen weerspiegelt. Next.js biedt verschillende manieren om gegevens te herwalideren:
- Pad Herwalideren: Valideer de cache voor een specifiek pad opnieuw.
- Tag Herwalideren: Valideer de cache voor gegevens die aan een specifieke tag zijn gekoppeld opnieuw.
Hier is een voorbeeld van het herwalideren van een pad na het aanmaken van een nieuw item:
// app/components/CreateItemForm.tsx
'use client';
import { useState } from 'react';
import { revalidatePath } from 'next/cache';
async function createItem(formData: FormData) {
'use server'
const name = formData.get('name') as string;
// Simuleer database interactie
console.log('Item aanmaken:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simuleer latentie
console.log('Item succesvol aangemaakt!');
revalidatePath('/items'); // Valideer het pad /items opnieuw
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState<string | null>(null);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
try {
await createItem(formData);
} catch (error: any) {
setErrorMessage(error.message || 'Er is een fout opgetreden.');
} finally {
setIsSubmitting(false);
}
}
return (
{errorMessage && <p style={{ color: 'red' }}>{errorMessage}</p>}
);
}
Uitleg:
- De functie
revalidatePath('/items')
ongeldigt de cache voor het/items
pad, zodat het volgende verzoek naar dat pad de nieuwste gegevens ophaalt.
Best Practices voor Server Actions
Om de voordelen van Server Actions te maximaliseren, overweeg de volgende best practices:
- Houd Server Actions Klein en Gefocust: Server Actions moeten een enkele, goed gedefinieerde taak uitvoeren. Vermijd complexe logica binnen Server Actions om leesbaarheid en testbaarheid te behouden.
- Gebruik Beschrijvende Namen: Geef uw Server Actions beschrijvende namen die duidelijk hun doel aangeven.
- Handel Fouten Gratieus Af: Implementeer robuuste foutafhandeling om informatieve feedback aan de gebruiker te geven en applicatiecrashes te voorkomen.
- Valideer Gegevens Grondig: Voer uitgebreide gegevensvalidatie uit om gegevensintegriteit te waarborgen en beveiligingskwetsbaarheden te voorkomen.
- Beveilig Uw Server Actions: Implementeer authenticatie- en autorisatiemechanismen om gevoelige gegevens en functionaliteit te beschermen.
- Optimaliseer Prestaties: Monitor de prestaties van uw Server Actions en optimaliseer ze indien nodig om snelle reactietijden te garanderen.
- Maak Effectief Gebruik van Caching: Maak gebruik van de cachingmechanismen van Next.js om prestaties te verbeteren en de belasting van de database te verminderen.
Veelvoorkomende Valen en Hoe Ze te Vermijden
Hoewel Server Actions tal van voordelen bieden, zijn er enkele veelvoorkomende valen waar u rekening mee moet houden:
- Te Complexe Server Actions: Vermijd het plaatsen van te veel logica in één Server Action. Splits complexe taken op in kleinere, beter beheersbare functies.
- Foutafhandeling Negeren: Neem altijd foutafhandeling op om onverwachte fouten op te vangen en nuttige feedback aan de gebruiker te geven.
- Beveiligingsbest Practices Negeren: Volg beveiligingsbest practices om uw applicatie te beschermen tegen veelvoorkomende bedreigingen zoals XSS en CSRF.
- Vergeten Gegevens te Herwalideren: Zorg ervoor dat u gecachte gegevens herwalideert nadat een Server Action gegevens heeft gewijzigd om de UI up-to-date te houden.
Conclusie
Next.js 14 Server Actions bieden een krachtige en efficiënte manier om formulierinzendingen en gegevensmutaties direct op de server af te handelen. Door de best practices te volgen die in deze gids worden uiteengezet, kunt u robuuste, veilige en performante webapplicaties bouwen. Omarm Server Actions om uw code te vereenvoudigen, de beveiliging te verbeteren en de algehele gebruikerservaring te verbeteren. Houd bij het integreren van deze principes rekening met de wereldwijde impact van uw ontwikkelkeuzes. Zorg ervoor dat uw formulieren en gegevensverwerkingsprocessen toegankelijk, veilig en gebruiksvriendelijk zijn voor diverse internationale doelgroepen. Deze toewijding aan inclusiviteit zal niet alleen de bruikbaarheid van uw applicatie verbeteren, maar ook het bereik en de effectiviteit ervan op wereldwijde schaal vergroten.