Sveobuhvatan vodič za Next.js 14 poslužiteljske akcije, koji pokriva najbolje prakse rukovanja obrascima, validaciju podataka, sigurnosna razmatranja i napredne tehnike za izradu modernih web aplikacija.
Next.js 14 poslužiteljske akcije: Ovladavanje najboljim praksama za rukovanje obrascima
Next.js 14 uvodi moćne značajke za izradu performantnih i korisnički prihvatljivih web aplikacija. Među njima se ističu poslužiteljske akcije (Server Actions) kao transformativan način rukovanja podnošenjem obrazaca i mutacijama podataka izravno na poslužitelju. Ovaj vodič pruža sveobuhvatan pregled poslužiteljskih akcija u Next.js 14, s naglaskom na najbolje prakse za rukovanje obrascima, validaciju podataka, sigurnost i napredne tehnike. Istražit ćemo praktične primjere i pružiti primjenjive uvide koji će vam pomoći u izgradnji robusnih i skalabilnih web aplikacija.
Što su Next.js poslužiteljske akcije?
Poslužiteljske akcije su asinkrone funkcije koje se izvršavaju na poslužitelju i mogu se pozvati izravno iz React komponenata. One eliminiraju potrebu za tradicionalnim API rutama za rukovanje podnošenjem obrazaca i mutacijama podataka, što rezultira pojednostavljenim kodom, poboljšanom sigurnošću i unaprijeđenim performansama. Poslužiteljske akcije su React poslužiteljske komponente (React Server Components - RSCs), što znači da se izvršavaju na poslužitelju, dovodeći do bržeg početnog učitavanja stranica i boljeg SEO-a.
Ključne prednosti poslužiteljskih akcija:
- Pojednostavljeni kod: Smanjite ponavljajući kod eliminiranjem potrebe za odvojenim API rutama.
- Poboljšana sigurnost: Izvršavanje na strani poslužitelja minimizira ranjivosti na strani klijenta.
- Unaprijeđene performanse: Izvršavajte mutacije podataka izravno na poslužitelju za brže vrijeme odziva.
- Optimizirani SEO: Iskoristite renderiranje na strani poslužitelja za bolje indeksiranje od strane tražilica.
- Tipska sigurnost: Iskoristite prednosti end-to-end tipske sigurnosti uz TypeScript.
Postavljanje vašeg Next.js 14 projekta
Prije nego što zaronite u poslužiteljske akcije, provjerite imate li postavljen Next.js 14 projekt. Ako počinjete od nule, kreirajte novi projekt koristeći sljedeću naredbu:
npx create-next-app@latest my-next-app
Pobrinite se da vaš projekt koristi app
strukturu direktorija kako biste u potpunosti iskoristili poslužiteljske komponente i akcije.
Osnovno rukovanje obrascima s poslužiteljskim akcijama
Krenimo s jednostavnim primjerom: obrazac koji podnosi podatke za stvaranje nove stavke u bazi podataka. Koristit ćemo jednostavan obrazac s jednim poljem za unos i gumbom za podnošenje.
Primjer: Stvaranje nove stavke
Prvo, definirajte funkciju poslužiteljske akcije unutar vaše React komponente. Ova funkcija će rukovati logikom podnošenja obrasca na poslužitelju.
// app/components/CreateItemForm.tsx
'use client';
import { useState } from 'react';
async function createItem(formData: FormData) {
'use server'
const name = formData.get('name') as string;
// Simulacija interakcije s bazom podataka
console.log('Stvaranje stavke:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulacija latencije
console.log('Stavka uspješno stvorena!');
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
await createItem(formData);
setIsSubmitting(false);
}
return (
);
}
Objašnjenje:
- Direktiva
'use client'
označava da je ovo klijentska komponenta. - Funkcija
createItem
označena je direktivom'use server'
, što ukazuje da je to poslužiteljska akcija. - Funkcija
handleSubmit
je funkcija na strani klijenta koja poziva poslužiteljsku akciju. Također upravlja stanjem korisničkog sučelja, poput onemogućavanja gumba tijekom podnošenja. - Atribut
action
elementa<form>
postavljen je na funkcijuhandleSubmit
. - Metoda
formData.get('name')
dohvaća vrijednost polja za unos 'name'. await new Promise
simulira operaciju baze podataka i dodaje latenciju.
Validacija podataka
Validacija podataka ključna je za osiguravanje integriteta podataka i sprječavanje sigurnosnih ranjivosti. Poslužiteljske akcije pružaju izvrsnu priliku za provođenje validacije na strani poslužitelja. Ovaj pristup pomaže u ublažavanju rizika povezanih isključivo s validacijom na strani klijenta.
Primjer: Validacija ulaznih podataka
Izmijenite poslužiteljsku akciju createItem
kako biste uključili logiku validacije.
// 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('Naziv stavke mora imati najmanje 3 znaka.');
}
// Simulacija interakcije s bazom podataka
console.log('Stvaranje stavke:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulacija latencije
console.log('Stavka uspješno stvorena!');
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
try {
await createItem(formData);
} catch (error: any) {
setErrorMessage(error.message || 'Došlo je do pogreške.');
} finally {
setIsSubmitting(false);
}
}
return (
{errorMessage && {errorMessage}
}
);
}
Objašnjenje:
- Funkcija
createItem
sada provjerava je liname
valjan (najmanje 3 znaka dug). - Ako validacija ne uspije, baca se pogreška.
- Funkcija
handleSubmit
ažurirana je tako da hvata sve pogreške koje baci poslužiteljska akcija i prikazuje poruku o pogrešci korisniku.
Korištenje biblioteka za validaciju
Za složenije scenarije validacije, razmislite o korištenju biblioteka za validaciju kao što su:
- Zod: TypeScript-first biblioteka za deklaraciju i validaciju shema.
- Yup: JavaScript graditelj shema za parsiranje, validaciju i transformaciju vrijednosti.
Evo primjera korištenja Zoda:
// app/utils/validation.ts
import { z } from 'zod';
export const CreateItemSchema = z.object({
name: z.string().min(3, 'Naziv stavke mora imati najmanje 3 znaka.'),
});
// 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 };
}
// Simulacija interakcije s bazom podataka
console.log('Stvaranje stavke:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulacija latencije
console.log('Stavka uspješno stvorena!');
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
try {
await createItem(formData);
} catch (error: any) {
setErrorMessage(error.message || 'Došlo je do pogreške.');
} finally {
setIsSubmitting(false);
}
}
return (
{errorMessage && {errorMessage}
}
);
}
Objašnjenje:
CreateItemSchema
definira pravila validacije za poljename
pomoću Zoda.- Metoda
safeParse
pokušava validirati ulazne podatke. Ako validacija ne uspije, vraća objekt s pogreškama. - Objekt
errors
sadrži detaljne informacije o neuspjelim validacijama.
Sigurnosna razmatranja
Poslužiteljske akcije poboljšavaju sigurnost izvršavanjem koda na poslužitelju, ali i dalje je ključno slijediti najbolje sigurnosne prakse kako biste zaštitili svoju aplikaciju od uobičajenih prijetnji.
Sprječavanje Cross-Site Request Forgery (CSRF) napada
CSRF napadi iskorištavaju povjerenje koje web stranica ima u korisnikov preglednik. Kako biste spriječili CSRF napade, implementirajte mehanizme za zaštitu od CSRF-a.
Next.js automatski rukuje zaštitom od CSRF-a kada se koriste poslužiteljske akcije. Framework generira i provjerava CSRF token za svako podnošenje obrasca, osiguravajući da zahtjev potječe iz vaše aplikacije.
Rukovanje autentifikacijom i autorizacijom korisnika
Osigurajte da samo autorizirani korisnici mogu izvršavati određene akcije. Implementirajte mehanizme za autentifikaciju i autorizaciju kako biste zaštitili osjetljive podatke i funkcionalnosti.
Evo primjera korištenja NextAuth.js za zaštitu poslužiteljske akcije:
// 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('Neautorizirano');
}
const name = formData.get('name') as string;
// Simulacija interakcije s bazom podataka
console.log('Stvaranje stavke:', name, 'od strane korisnika:', session.user?.email);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulacija latencije
console.log('Stavka uspješno stvorena!');
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
try {
await createItem(formData);
} catch (error: any) {
setErrorMessage(error.message || 'Došlo je do pogreške.');
} finally {
setIsSubmitting(false);
}
}
return (
{errorMessage && {errorMessage}
}
);
}
Objašnjenje:
- Funkcija
getServerSession
dohvaća informacije o korisničkoj sesiji. - Ako korisnik nije autentificiran (nema sesije), baca se pogreška, sprječavajući izvršavanje poslužiteljske akcije.
Sanitizacija ulaznih podataka
Sanitizirajte ulazne podatke kako biste spriječili Cross-Site Scripting (XSS) napade. XSS napadi se događaju kada se zlonamjerni kod ubaci na web stranicu, potencijalno ugrožavajući korisničke podatke ili funkcionalnost aplikacije.
Koristite biblioteke poput DOMPurify
ili sanitize-html
za sanitizaciju korisničkih unosa prije njihove obrade u vašim poslužiteljskim akcijama.
Napredne tehnike
Sada kada smo pokrili osnove, istražimo neke napredne tehnike za učinkovito korištenje poslužiteljskih akcija.
Optimistična ažuriranja
Optimistična ažuriranja pružaju bolje korisničko iskustvo trenutnim ažuriranjem korisničkog sučelja kao da će akcija uspjeti, čak i prije nego što poslužitelj to potvrdi. Ako akcija ne uspije na poslužitelju, korisničko sučelje se vraća u prethodno stanje.
// 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;
// Simulacija interakcije s bazom podataka
console.log('Ažuriranje stavke:', id, 's nazivom:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulacija latencije
// Simulacija neuspjeha (za demonstracijske svrhe)
const shouldFail = Math.random() < 0.5;
if (shouldFail) {
throw new Error('Ažuriranje stavke nije uspjelo.');
}
console.log('Stavka uspješno ažurirana!');
return { name }; // Vrati ažurirani naziv
}
export default function UpdateItemForm({ id, initialName }: { id: string; initialName: string }) {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
const [itemName, setItemName] = useState(initialName);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
// Optimistično ažuriraj korisničko sučelje
const newName = formData.get('name') as string;
setItemName(newName);
try {
const result = await updateItem(id, formData);
//Ako je uspješno, ažuriranje je već vidljivo u sučelju putem setItemName
} catch (error: any) {
setErrorMessage(error.message || 'Došlo je do pogreške.');
// Vrati korisničko sučelje u prethodno stanje u slučaju pogreške
setItemName(initialName);
} finally {
setIsSubmitting(false);
}
}
return (
Trenutni naziv: {itemName}
{errorMessage && {errorMessage}
}
);
}
Objašnjenje:
- Prije pozivanja poslužiteljske akcije, korisničko sučelje se odmah ažurira novim nazivom stavke pomoću
setItemName
. - Ako poslužiteljska akcija ne uspije, korisničko sučelje se vraća na izvorni naziv stavke.
Ponovna validacija podataka
Nakon što poslužiteljska akcija izmijeni podatke, možda ćete morati ponovno validirati keširane podatke kako biste osigurali da korisničko sučelje odražava najnovije promjene. Next.js pruža nekoliko načina za ponovnu validaciju podataka:
- Revalidate Path: Ponovno validiraj predmemoriju za određenu putanju.
- Revalidate Tag: Ponovno validiraj predmemoriju za podatke povezane s određenom oznakom (tagom).
Evo primjera ponovne validacije putanje nakon stvaranja nove stavke:
// 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;
// Simulacija interakcije s bazom podataka
console.log('Stvaranje stavke:', name);
await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulacija latencije
console.log('Stavka uspješno stvorena!');
revalidatePath('/items'); // Ponovno validiraj putanju /items
}
export default function CreateItemForm() {
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
async function handleSubmit(formData: FormData) {
setIsSubmitting(true);
setErrorMessage(null);
try {
await createItem(formData);
} catch (error: any) {
setErrorMessage(error.message || 'Došlo je do pogreške.');
} finally {
setIsSubmitting(false);
}
}
return (
{errorMessage && {errorMessage}
}
);
}
Objašnjenje:
- Funkcija
revalidatePath('/items')
poništava predmemoriju za putanju/items
, osiguravajući da sljedeći zahtjev za tu putanju dohvati najnovije podatke.
Najbolje prakse za poslužiteljske akcije
Kako biste maksimalno iskoristili prednosti poslužiteljskih akcija, razmotrite sljedeće najbolje prakse:
- Držite poslužiteljske akcije malima i fokusiranima: Poslužiteljske akcije trebale bi obavljati jedan, dobro definiran zadatak. Izbjegavajte složenu logiku unutar poslužiteljskih akcija kako biste održali čitljivost i mogućnost testiranja.
- Koristite opisna imena: Dajte svojim poslužiteljskim akcijama opisna imena koja jasno ukazuju na njihovu svrhu.
- Elegantno rukujte pogreškama: Implementirajte robusno rukovanje pogreškama kako biste korisniku pružili informativne povratne informacije i spriječili rušenje aplikacije.
- Temeljito validirajte podatke: Provedite sveobuhvatnu validaciju podataka kako biste osigurali integritet podataka i spriječili sigurnosne ranjivosti.
- Osigurajte svoje poslužiteljske akcije: Implementirajte mehanizme za autentifikaciju i autorizaciju kako biste zaštitili osjetljive podatke i funkcionalnosti.
- Optimizirajte performanse: Pratite performanse svojih poslužiteljskih akcija i optimizirajte ih po potrebi kako biste osigurali brzo vrijeme odziva.
- Učinkovito koristite keširanje: Iskoristite mehanizme keširanja Next.js-a za poboljšanje performansi i smanjenje opterećenja baze podataka.
Uobičajene zamke i kako ih izbjeći
Iako poslužiteljske akcije nude brojne prednosti, postoje neke uobičajene zamke kojih treba biti svjestan:
- Previše složene poslužiteljske akcije: Izbjegavajte stavljanje previše logike unutar jedne poslužiteljske akcije. Razbijte složene zadatke na manje, upravljivije funkcije.
- Zanemarivanje rukovanja pogreškama: Uvijek uključite rukovanje pogreškama kako biste uhvatili neočekivane pogreške i pružili korisne povratne informacije korisniku.
- Ignoriranje najboljih sigurnosnih praksi: Slijedite najbolje sigurnosne prakse kako biste zaštitili svoju aplikaciju od uobičajenih prijetnji poput XSS-a i CSRF-a.
- Zaboravljanje ponovne validacije podataka: Osigurajte da ponovno validirate keširane podatke nakon što poslužiteljska akcija izmijeni podatke kako bi korisničko sučelje ostalo ažurirano.
Zaključak
Next.js 14 poslužiteljske akcije pružaju moćan i učinkovit način za rukovanje podnošenjem obrazaca i mutacijama podataka izravno na poslužitelju. Slijedeći najbolje prakse navedene u ovom vodiču, možete izgraditi robusne, sigurne i performantne web aplikacije. Prihvatite poslužiteljske akcije kako biste pojednostavili svoj kod, poboljšali sigurnost i unaprijedili cjelokupno korisničko iskustvo. Dok integrirate ove principe, razmislite o globalnom utjecaju svojih razvojnih odabira. Osigurajte da su vaši obrasci i procesi rukovanja podacima pristupačni, sigurni i jednostavni za korištenje raznolikoj međunarodnoj publici. Ova predanost inkluzivnosti ne samo da će poboljšati upotrebljivost vaše aplikacije, već će i proširiti njezin doseg i učinkovitost na globalnoj razini.