Nederlands

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:

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:

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:

Validatiebibliotheken Gebruiken

Overweeg voor complexere validatiescenario's validatiebibliotheken zoals:

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:

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:

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:

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:

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:

Best Practices voor Server Actions

Om de voordelen van Server Actions te maximaliseren, overweeg de volgende best practices:

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:

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.