📘 Hướng Dẫn Sử Dụng Hook useActionState Trong React
Mục Lục
- Tại Sao Nên Sử Dụng
useActionState - Cú Pháp Cơ Bản
- Ví Dụ Cơ Bản
- Ví Dụ Với Nhiều Trường Nhập
- Ví Dụ Với Checkbox, Radio, và Select
- Lợi Ích Chính Của
useActionState - Thực Hành Tốt Nhất
- Những Cạm Bẫy Thường Gặp
- Mẹo Tối Ưu Hiệu Suất
- Khắc Phục Sự Cố
- Câu Hỏi Thường Gặp
🔹 Tại Sao Nên Sử Dụng useActionState?
Truyền thống, việc xử lý biểu mẫu trong React yêu cầu:
- Tạo nhiều hook
useStatecho từng trường nhập. - Viết một hàm
onSubmitvớievent.preventDefault(). - Quản lý trạng thái đang chờ/tải thủ công.
Cách tiếp cận này hoạt động, nhưng trở nên lặp đi lặp lại và lộn xộn khi các biểu mẫu phát triển.
React 19 đã giới thiệu hook useActionState để đơn giản hóa điều này:
- ✅ Không cần
useStatecho từng trường nhập. - ✅ Tự động xử lý trạng thái đang chờ (loading).
- ✅ Hoạt động liền mạch với Server Actions trong Next.js App Router.
- ✅ Cách quản lý gửi biểu mẫu gọn gàng và khai báo hơn.
Tóm lại:
👉 useActionState = một thay thế hiện đại cho onSubmit + useState.
🔹 Cú Pháp Cơ Bản
javascript
const [state, action, isPending] = useActionState(fn, initialState);
fn→ hàm bất đồng bộ chạy khi gửi biểu mẫu.initialState→ giá trị mặc định trước khi gửi.state→ kết quả trả về từfn.action→ hàm xử lý bạn truyền vào<form action={action}>.isPending→ boolean, true khi biểu mẫu đang được gửi.
🔹 Ví Dụ Cơ Bản
javascript
"use client";
import { useActionState } from "react";
async function submitForm(prevState, formData) {
const name = formData.get("name");
return `Xin chào, ${name}!`;
}
export default function SimpleForm() {
const [message, formAction, isPending] = useActionState(submitForm, "");
return (
<form action={formAction}>
<input type="text" name="name" placeholder="Nhập tên của bạn" />
<button type="submit" disabled={isPending}>
{isPending ? "Đang gửi..." : "Gửi"}
</button>
{message && <p>{message}</p>}
</form>
);
}
🔹 Ví Dụ Với Nhiều Trường Nhập
javascript
"use client";
import { useActionState } from "react";
async function registerUser(prevState, formData) {
const username = formData.get("username");
const email = formData.get("email");
const password = formData.get("password");
if (!email.includes("@")) {
return "❌ Địa chỉ email không hợp lệ!";
}
return `✅ Người dùng ${username} đã được đăng ký thành công!`;
}
export default function RegisterForm() {
const [result, formAction, isPending] = useActionState(registerUser, "");
return (
<form action={formAction}>
<input type="text" name="username" placeholder="Tên đăng nhập" required />
<br />
<input type="email" name="email" placeholder="Email" required />
<br />
<input type="password" name="password" placeholder="Mật khẩu" required />
<br />
<button type="submit" disabled={isPending}>
{isPending ? "Đang đăng ký..." : "Đăng ký"}
</button>
{result && <p>{result}</p>}
</form>
);
}
🔹 Ví Dụ Với Checkbox, Radio, và Select
javascript
"use client";
import { useActionState } from "react";
async function handleForm(prevState, formData) {
return {
gender: formData.get("gender"),
agree: formData.get("agree") === "on",
country: formData.get("country"),
};
}
export default function AdvancedForm() {
const [data, formAction, isPending] = useActionState(handleForm, null);
return (
<form action={formAction}>
{/* Radio */}
<label>
<input type="radio" name="gender" value="Male" /> Nam
</label>
<label>
<input type="radio" name="gender" value="Female" /> Nữ
</label>
<br />
{/* Checkbox */}
<label>
<input type="checkbox" name="agree" /> Tôi đồng ý với các điều khoản
</label>
<br />
{/* Select */}
<select name="country" defaultValue="">
<option value="">--Chọn Quốc Gia--</option>
<option value="Vietnam">Việt Nam</option>
<option value="USA">Mỹ</option>
<option value="India">Ấn Độ</option>
</select>
<br />
<button type="submit" disabled={isPending}>
{isPending ? "Đang xử lý..." : "Gửi"}
</button>
{data && (
<pre style={{ marginTop: "10px" }}>
{JSON.stringify(data, null, 2)}
</pre>
)}
</form>
);
}
🔹 Lợi Ích Chính Của useActionState
- ✅ Loại bỏ boilerplate (
useState+onSubmit). - ✅ Quản lý biểu mẫu gọn gàng, rõ ràng.
- ✅ Tự động quản lý trạng thái tải (
isPending). - ✅ Hoạt động với client và server actions.
- ✅ Tương lai bền vững với React 19 + Next.js App Router.
🔹 Thực Hành Tốt Nhất
- Giữ cho các hàm xử lý ngắn gọn: Tránh viết quá nhiều logic trong hàm xử lý để dễ bảo trì.
- Kiểm tra dữ liệu nhập: Đảm bảo kiểm tra dữ liệu đầu vào trước khi gửi để tránh lỗi.
- Sử dụng thông báo rõ ràng: Cung cấp phản hồi cho người dùng sau khi gửi biểu mẫu.
🔹 Những Cạm Bẫy Thường Gặp
- Quản lý trạng thái phức tạp: Nếu biểu mẫu trở nên phức tạp, hãy cân nhắc chia nhỏ thành các thành phần.
- Không thông báo lỗi: Đảm bảo cung cấp thông báo cho người dùng khi có lỗi xảy ra.
🔹 Mẹo Tối Ưu Hiệu Suất
- Sử dụng debounce cho các trường nhập: Giảm số lượng yêu cầu gửi khi người dùng nhập liệu.
- Tối ưu hóa hàm bất đồng bộ: Đảm bảo các hàm xử lý biểu mẫu không mất quá nhiều thời gian.
🔹 Khắc Phục Sự Cố
- Không nhận được phản hồi: Kiểm tra xem có lỗi trong hàm xử lý không.
- Trạng thái không thay đổi: Đảm bảo rằng
actionđược cập nhật chính xác.
🔹 Câu Hỏi Thường Gặp
useActionState có hoạt động với các biểu mẫu lớn không?
Có, nó được thiết kế để xử lý các biểu mẫu phức tạp một cách dễ dàng và hiệu quả.
Tôi có thể sử dụng useActionState với các thư viện khác không?
Có, bạn có thể tích hợp useActionState với các thư viện như Formik hay React Hook Form.
⚡ Tóm lại:
useActionState giúp đơn giản hóa, làm sạch và sẵn sàng cho các ứng dụng React hiện đại.
Bạn có muốn tôi bao gồm một phiên bản Next.js Server Action (nơi hành động chạy hoàn toàn trên máy chủ thay vì máy khách) không?