Để hiểu Actions, trước tiên hãy xem cách chúng tôi quản lý biểu mẫu bây giờ. Trong React 18 trở về trước, chúng ta gửi Form bằng hàm handSubmit trong một button. Đây là một Form đơn giản có 1 input trường “name”:
// Form submission in React 18
console.info('React 18 form');
const [name, setName] = useState('');
const [isPending, setIsPending] = useState(false);
const handleChange = (event) => {
setName(event.target.value);
};
const handleSubmit = (event) => {
event.preventDefault();
setIsPending(true);
setTimeout(() => {
// call API
setIsPending(false);
}, 500);
};
return (
< form >
< input type="text" name="name" onChange={handleChange} />
{isPending ? < p >Loading...< /p > : < p >Hello in React 18, {name}< /p >}
< button onClick={handleSubmit} disabled={isPending} >
Update
</ button >
</ form >
);
Trong mã này, chúng ta đang làm như sau:
Thêm loading state: Chúng tôi sử dụng biến isPending để theo dõi loading state theo cách thủ công.
Gửi Form: Form được gửi bằng cách sử dụng trình xử lý sự kiện handSubmit được đính kèm với sự kiện onClick của button.
Ghi lại giá trị đã gửi: Hàm handChange ghi lại giá trị đã gửi và lưu trữ nó trong các biến state.
React Actions là gì?
Với React 19, việc xử lý các Form trở nên dễ dàng hơn với Actions, lấy cảm hứng từ các framework như Remix. Một tính năng chính là việc sử dụng startTransition nâng cao để quản lý các state đang chờ xử lý.
startTransition được giới thiệu trong React 18, cho phép các nhà phát triển đánh dấu một số cập nhật nhất định là ít khẩn cấp hơn.
Trong React 19, startTransition giờ đây có thể xử lý các hàm không đồng bộ, khiến nó trở nên mạnh mẽ hơn trong việc quản lý các tác vụ không đồng bộ và cải thiện trải nghiệm người dùng trong quá trình gửi Form.
const [isPending, startTransition] = useTransition();
const handleSubmit = () => {
startTransition(async () => {
const error = await updateName(name);
if (error) {
setError(error);
return;
}
redirect('/path');
});
};
Hàm không đồng bộ “updateName” bên trong startTransition được gọi là Action. Điều khiến các Actions trở nên thú vị là chúng có thể được sử dụng trực tiếp để gửi các Form như sau:
< form action="{actionFn}">...</ form >
Định dạng này có thể trông quen thuộc nếu bạn có kinh nghiệm với PHP.
Làm thế nào để tạo React Action
Để tạo hàm async, chúng ta có thể sử dụng một hook mới được giới thiệu trong React 19 có tên là useActionState. Chúng ta truyền vào hook một hàm hành động và khởi tạo state. Hook này trả về state được cập nhật và một hành động Form actionFn, có thể được sử dụng để kết nối một Form.
const [state, actionFn] = useActionState(submitAction, { name: '' });
Kết nối với Form:
< form action={actionFn} >
< input type="text" name="name" />
< button type="submit" disabled="{pending}" >
Update
</ button >
</ form >
Để add loading state, chúng ta có thể sử dụng hook mới được giới thiệu trong React 19 có tên là useFormStatus.
const { pending, data, method, action } = useFormStatus();
Hook này cung cấp thông tin về state của Form. State đang chờ xử lý cho biết liệu Form có được gửi hay không và dữ liệu là đối tượng FormData chứa dữ liệu đã gửi. Chúng tôi sử dụng pending state này để hiển thị loader.
Nhưng có một lưu ý: hook này chỉ có thể được sử dụng trong component con chứ không phải trong chính Form. Vì vậy, chúng ta phải tạo các component con như SubmitButton và Loader để lấy pending state
function Loader() {
const { pending } = useFormStatus();
return <div>{pending && "Loading..."}</div>;
}
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
Update
</button>
);
}
....
return (
<form action={formAction}>
<input type="text" name="name" />
<Loader />
<SubmitButton />
</form>
)
Chúng tôi cũng có thể nắm bắt thông tin cần thiết về dữ liệu được gửi tới Form bằng cách truy xuất dữ liệu đó từ state được trả về từ useActionState.
const [state, formAction] = useActionState(submitAction, { name: '' });
Đây là đoạn mã đầy đủ:
function Loader() {
const { pending } = useFormStatus();
return <div>{pending && 'Loading...'}</div>;
}
function SubmitButton() {
const { pending } = useFormStatus();
return (
<button type="submit" disabled={pending}>
Update
</button>
);
}
function Name({ name }) {
return <p>Hello in 19 {name}</p>;
}
function App() {
console.info('React 19 form');
const [state, formAction] = useActionState(submitAction, { name: '' });
return (
<form action={formAction}>
<input type="text" name="name" />
<Loader />
<SubmitButton />
<Name name={state?.name} />
</form>
);
}
Kết Luận
Bằng cách sử dụng Actions cùng với các hook như useActionState và useFormStatus, chúng tôi có thể dễ dàng quản lý states của Form, thu thập dữ liệu đã gửi và cung cấp phản hồi cho người dùng trong quá trình gửi Form để hiển thị pending states
Nguồn dịch(https://www.freecodecamp.org/news/react-19-actions-simpliy-form-submission-and-loading-states/)