Hướng dẫn toàn diện về Server Actions trong Next.js 15: xử lý form, validate dữ liệu với Zod, quản lý optimistic updates và bảo mật mutation.
Server Actions trong Next.js 15 không chỉ là một cách viết code tiện hơn, mà là sự thay đổi tư duy căn bản trong cách ứng dụng React giao tiếp với backend. Thay vì phải dựng REST API riêng, viết endpoint /api/..., rồi dùng fetch hay React Query để gọi, bạn có thể gọi trực tiếp hàm async chạy trên server ngay từ client component hoặc form native.
Khi bạn đánh dấu 'use server' ở đầu file hoặc bên trong một hàm, Next.js sẽ tự động tạo một POST endpoint ẩn với mã băm bảo mật (action ID). Trình duyệt gửi request dưới dạng multipart/form-data hoặc application/json, Next.js giải mã và thực thi hàm trên máy chủ Node.js.
'use server';
import { z } from 'zod';
import { db } from '@/lib/db';
import { revalidatePath } from 'next/cache'
Đặt câu hỏi, chia sẻ ý kiến hoặc góp ý giải pháp kỹ thuật cùng cộng đồng.
Khám phá tiếp
Đọc thẳng process.env khiến lỗi cấu hình chỉ lộ ra khi khách đã bấm thanh toán. Dùng Zod để app crash ngay lúc boot, kèm thông báo chỉ rõ biến nào sai.
Hướng dẫn xây dựng cache layer với Redis cho API và Server Components: xử lý cache stampede, eviction policy và cơ chế invalidate dữ liệu realtime.
Cấu hình Nginx reverse proxy cho Next.js: cache asset, nén gzip, giới hạn request và những lỗi timeout thường gặp khi chạy trên VPS nhỏ.
Next.js 15 đi kèm với React 19, thay thế hook thử nghiệm useFormState bằng useActionState chuẩn:
'use client';
import { useActionState } from 'react';
import { updateProfile } from '@/server/actions/user';
export function ProfileForm() {
const [state, formAction, isPending] = useActionState(updateProfile, null);
return (
<form action={formAction} className="space-y-4">
<input name="name" placeholder="Họ và tên" className="input" />
<textarea name="bio" placeholder="Giới thiệu bản thân" className="textarea" />
<button type="submit" disabled={isPending} className="btn-primary">
{isPending ? 'Đang cập nhật...' : 'Lưu thay đổi'}
</button>
</form>
);
}