Nếu bạn đang tìm hiểu về React hiện đại — đặc biệt là với React Server Components — thì có một hook mạnh mẽ nhưng ít người biết đến mà bạn nên làm quen: useActionState
Hook này có mặt trong các bản build experimental và Canary của React, và nó mang lại một cách quản lý state liên quan đến form thông minh hơn, được gắn trực tiếp với quá trình gửi form.
Trong bài viết này, chúng ta sẽ phân tích useActionState
là gì, lý do tại sao nó hữu ích, và đi qua các ví dụ thực tế để bạn có thể tự tin tích hợp nó vào ứng dụng của mình.
useActionState
là gì?
useActionState
là một hook trong React được thiết kế để xử lý việc cập nhật state xảy ra sau khi một form được gửi.
Hãy nghĩ về nó như một cách khai báo rõ ràng hơn để xử lý kết quả của một hành động — chẳng hạn như gửi dữ liệu lên server hoặc xác thực một trường thông tin.
Cú pháp:
const [state, formAction] = useActionState(fn, initialState, permalink?);
Trong đó:
- fn: Một hàm được gọi khi form được submit. Nó nhận vào prevState (state trước đó) và formData.
- initialState: Giá trị mặc định trước khi có bất kỳ submission nào.
- permalink (tuỳ chọn): Một URL dùng để giữ lại state (rất phù hợp với Server Components).
Trả về:
- state: State hiện tại của form.
- formAction: Một hàm handler mà bạn truyền vào prop action của thẻ
<form>
.
Ví dụ 1: Form tăng số đơn giản
Giả sử bạn muốn có một nút bấm để tăng giá trị của bộ đếm mỗi khi được click (tức là gửi form). Đây là cách làm:
import { useActionState } from 'react'; async function increment(prevState, formData) { return prevState + 1;
} function CounterForm() { const [count, formAction] = useActionState(increment, 0); return ( <form action={formAction}> <p>Counter: {count}</p> <button type="submit">Increment</button> </form> );
}
Mỗi lần form được submit, hàm increment
sẽ được chạy và cập nhật bộ đếm.
Ví dụ 2: Hiển thị thông báo lỗi trong form
Bạn có thể dùng useActionState
để hiển thị thông báo lỗi khi việc gửi form thất bại — rất hữu ích trong các form có xác thực từ backend.
import { useActionState } from 'react';
import { addToCart } from './actions.js'; function AddToCartForm({ itemID, itemTitle }) { const [message, formAction] = useActionState(addToCart, null); return ( <form action={formAction}> <h2>{itemTitle}</h2> <input type="hidden" name="itemID" value={itemID} /> <button type="submit">Add to Cart</button> {message && <p className="error">{message}</p>} </form> );
} // actions.js (server function)
"use server"; export async function addToCart(prevState, formData) { const itemID = formData.get('itemID'); if (itemID === "1") { return "Added to cart"; } else { return "Couldn't add to cart: the item is sold out."; }
}
Mẫu này giúp bạn xử lý và hiển thị lỗi từ server mà không cần viết nhiều mã rườm rà.
Ví dụ 3: Giữ nguyên state form khi chuyển trang
Khi dùng thêm tham số permalink
, useActionState
có thể giữ lại trạng thái của form kể cả khi người dùng rời trang và quay lại.
import { useActionState } from 'react';
import { submitFeedback } from './actions.js'; function FeedbackForm() { const [feedback, formAction] = useActionState(submitFeedback, '', '/feedback'); return ( <form action={formAction}> <textarea name="feedback" placeholder="Your feedback" /> <button type="submit">Submit</button> <p>{feedback}</p> </form> );
}
Điều này đảm bảo trạng thái form vẫn còn khi điều hướng trang — cải thiện UX đáng kể, nhất là với form nhiều bước hoặc bố cục dạng persistent layout.
Khi nào không nên dùng useActionState
?
Dù hook này rất mạnh mẽ, nhưng không phải lúc nào cũng phù hợp:
- List Keys: Không nên dùng để tạo key trong danh sách — hãy dùng ID ổn định và duy nhất từ dữ liệu.
- ID do người dùng kiểm soát: Nếu bạn lấy ID hoặc state từ cơ sở dữ liệu/API, bạn không cần đến useActionState.
- UI động cao: Nếu bạn cần cập nhật state ở mỗi lần render (ví dụ như animation hoặc trạng thái tạm thời), hãy dùng useRef hoặc useState cục bộ.
Tổng kết
useActionState
là một công cụ tuyệt vời để xử lý form trong React, đặc biệt là khi sử dụng Server Components.
Nó cho bạn quyền kiểm soát tốt hơn đối với kết quả form, dễ dàng xử lý thông báo lỗi, và hỗ trợ lưu state form qua các route.
Nếu bạn đang khám phá các tính năng mới nhất của React, việc thêm hook này vào "hộp công cụ" là điều hiển nhiên.
Chúc bạn code vui vẻ!