Sử dụng form trong Next.js có nhiều cách, từ cách truyền thống , dùng các hook nhuêu usestate, useref, hoặc dùng Server Action,…
Trong phát triển web, form là thành phần quan trọng giúp thu thập dữ liệu từ người dùng. Khi làm việc với Next.js, bạn có nhiều cách để xử lý form, từ phương pháp truyền thống đến các thư viện hiện đại tối ưu hiệu suất. Bài này sẽ hướng dẫn cách sử dụng form trong Next.js 15 với nhiều phương pháp khác nhau, từ đơn giản đến nâng cao, bao gồm:
- HTML Form cơ bản : cách truyền thống, không cần JavaScript
- useState để kiểm soát form , phù hợp với React
- useRef : để tránh re-render không cần thiết
- Formik : để quản lý form hiệu quả
- React Hook Form : để tối ưu hiệu suất
- Server Actions của Next.js 15 : để xử lý form trực tiếp trên server
Sử dụng HTML Form cơ bản
Cách đơn giản nhất là sử dụng thẻ <form> và xử lý dữ liệu trong một API route. Thực hiện như sau:
Tạo form đơn giản trong trang Next.js:
//app/BasicForm/page.tsx
export default function BasicForm() {
return (
<form action="/api/form-handler" method="POST" className="w-[300px]">
<input type="text" name="username" placeholder="Nhập tên" className="border" />
<button type="submit" className="bg-gray-300 px-3">Gửi</button>
</form>
)}
Tạo API route để xử lý dữ liệu:
//app/api/form-handler/route.ts
import { NextRequest, NextResponse } from "next/server";
export async function POST(req: NextRequest) {
const formData = await req.formData();
const username = formData.get("username");
return NextResponse.json({ message: `Xin chào, ${username}!` });
}
Cách này sử dụng hành động submit mặc định của trình duyệt, gửi dữ liệu đến API để xử lý

Sử dụng React state để kiểm soát form
Sử dụng useState để cập nhật giá trị form theo thời gian thực.
// app/ControlledForm/page.tsx
"use client";
import { useState } from "react";
export default function ControlledForm() {
const [name, setName] = useState("");
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
alert(`Tên đã nhập: ${name}`);
};
return (
<form onSubmit={handleSubmit} >
<input type="text" placeholder="Nhập tên" className="border"
value={name} onChange={(e) => setName(e.target.value)} />
{name}
<button type="submit" className="bg-gray-300 px-3 block">
Gửi
</button>
</form>
)}

Cách này giúp cập nhật trạng thái form ngay khi người dùng nhập.
Sử dụng server action trong Next.JS 15
Next.js 15 hỗ trợ server actions giúp gửi dữ liệu lên server dễ dàng hơn.
Tạo form: app/ServerActionForm/page.tsx
// app/ServerActionForm/page.tsx
import handleSubmit from "../handleSubmit"
export default function ServerActionForm() {
return (
<form action={handleSubmit}>
<input type="text" name="username" placeholder="Nhập tên" />
<button type="submit">Gửi</button>
</form>
)}
Xử lý dữ liệu trên server:
// app/handleSubmit.ts
"use server";
export default async function handleSubmit(formData: FormData) {
const username = formData.get("username");
console.log("Dữ liệu:", username);
}

Đây là cách tiếp cận tối ưu trong Next.js 15.
Sử dụng useRef để quản ký form (tránh re-render)
useRef giúp truy cập trực tiếp vào DOM mà không gây re-render khi nhập dữ liệu. Phù hợp khi bạn không cần kiểm tra dữ liệu trong quá trình nhập.
// app/RefForm/page.tsx
"use client";
import { useRef } from "react";
export default function RefForm() {
const inputRef = useRef<HTMLInputElement>(null);
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
alert(`Tên đã nhập: ${inputRef.current?.value}`);
};
return (
<form onSubmit={handleSubmit}>
<input ref={inputRef} type="text" placeholder="Nhập tên"
className= "border" />
<button type="submit"
className="bg-gray-300 px-3 block"> Gửi
</button>
</form>
)}
Ưu điểm & Nhược điểm
- Tránh re-render không cần thiết (không giống useState).
- Dễ dùng cho form nhỏ, không cần kiểm tra dữ liệu khi nhập.
- Không thể kiểm soát dữ liệu theo thời gian thực.
- Không phù hợp với form lớn hoặc có nhiều logic.

Các cách sau là bổ sung, mời bạn đọc nếu thích
Sử dụng formik
Module Formik giúp quản lý form hiệu quả hơn, đặc biệt là khi có nhiều field. Muốn dùng thì cài thêm vào dự án với lệnh npm install formik yup
Tạo file app/FormikForm/page.tsx
// app/FormikForm/page.tsx
"use client";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";
const validationSchema = Yup.object({
username: Yup.string().required("Tên không được để trống"),
});
export default function FormikForm() {
return (
<Formik
initialValues={{ username: "" }}
validationSchema={validationSchema}
onSubmit={(values) => alert(`Tên: ${values.username}`)} >
{() => (
<Form>
<Field type="text" name="username"
placeholder="Nhập tên" className="border" />
<ErrorMessage name="username" component="div"
className="text-red-500 text-[12px]" />
<button type="submit"
className="bg-gray-300 px-3 block ">Gửi
</button>
</Form>
)}
</Formik>
)}
Cách này giúp kiểm tra dữ liệu đầu vào dễ dàng.

Sử dụng react hook form
React Hook Form nhẹ hơn Formik và tối ưu hiệu suất. Muốn dùng thì cài đặt module với lệnh npm install react-hook-form
Tạo file : app/HookForm/page.tsx
// app/HookForm/page.tsx
"use client";
import { useForm } from "react-hook-form";
export default function HookForm() {
const { register, handleSubmit } = useForm();
const onSubmit = (data: any) => alert(`Tên: ${data.username}`);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input {...register("username", { required: true })}
placeholder="Nhập tên" className="border" />
<button type="submit" className="bg-gray-300 px-3 block">
Gửi
</button>
</form>
)}

React Hook Form hoạt động nhanh và hỗ trợ dễ dàng.
So sánh các cách thức:
Phương pháp | Ưu điểm | Nhược điểm |
HTML Form | Dễ triển khai, không cần JavaScript | Không thể kiểm soát form động |
React State | Kiểm soát tốt dữ liệu nhập | Cập nhật state liên tục có thể giảm hiệu suất |
Formik | Quản lý form dễ dàng, hỗ trợ validation | Hơi nặng, cần học cách dùng |
React Hook Form | Nhẹ, dễ dùng, tối ưu hiệu suất | Hơi khó dùng với field động |
Server Actions | Tích hợp với Next.js 15, không cần client JS | Chưa phổ biến rộng rãi |
Sử dụng form trong Next.js phong phú, nhiều cách nhưng dễ dùng thôi, tùy bạn có thể linh hoạt sử dụng tùy nhu cầu, sở thích và mức độ phức tạp của form,…
Xem thêm các link này nhé nếu muốn https://nextjs.org/docs/app/api-reference/components/form, https://nextjs.org/docs/pages/building-your-application/data-fetching/forms-and-mutations