Controller là gì và tại sao phải dùng tới nó?
Trong React Hook Form, thông thường chúng ta sử dụng register để đăng ký các input thông thường như <input>, <textarea> hoặc <select>. Tuy nhiên, với các component phức tạp hơn từ các thư viện UI (ví dụ: Ant Design, Material-UI, React Select, v.v.) hoặc các thành phần tùy chỉnh mà không cung cấp thuộc tính ref để register có thể truy cập, Controller trở nên vô cùng hữu ích.
Controller đóng vai trò là một "cầu nối", cho phép React Hook Form kiểm soát và quản lý trạng thái của các component này, bao gồm cả validation (kiểm tra hợp lệ) và giá trị của chúng.
Các thành phần chính
Các thành phần chính bao gồm: control, name, Controller, field, rules, render
Controller
Kết nối một component UI (HTML hoặc custom) với React Hook Form.
control
const { control } = useForm();
control là đối tượng quan trọng nhất được trả về từ useForm(). Nó chứa các phương thức và trạng thái cần thiết để Controller có thể tương tác với form. Bạn phải truyền control vào prop control của Controller.
name
Prop name của Controller là một chuỗi xác định tên của trường input trong dữ liệu form của bạn. Nó giống như thuộc tính name trên một input HTML thông thường và sẽ là key để truy cập giá trị của trường đó trong đối tượng data khi form được submit.const onSubmit = (data: any) => {
console.log("Selected city:", data.city);
};
<form onSubmit={handleSubmit(onSubmit)}>
<Controller
name="city"
....
<select>
...
</select>
/>
</form>
Console.log data.city sẽ in ra giá trị được chọn từ Select
rules
Prop rules cho phép bạn định nghĩa các quy tắc validation cho trường input. Nó nhận một đối tượng chứa các quy tắc như required, minLength, maxLength, pattern, v.v.
<Controller
name="city"
control={control}
rules={{ required: "Bạn phải chọn thành phố" }}
render={({ field }) => (
<select {...field}
//{...register("city", { required: "Hãy chọn một thành phố" })}
>
...
</select>
/>
render
Prop render là một hàm (render prop) nhận một đối tượng làm đối số. Đối tượng này chứa các props cần thiết để bạn "kết nối" component UI của mình với React Hook Form. Quan trọng nhất, nó chứa thuộc tính field.
field
Khi bạn sử dụng render={({ field }) => (...), bạn đang ủy quyền việc quản lý giá trị và sự kiện thay đổi cho React Hook Form thông qua đối tượng field. Cụ thể:
- value: React Hook Form sẽ tự động cung cấp giá trị hiện tại của trường thông qua field.value. Khi bạn sử dụng ...field trên <select>, value sẽ tự động được gán cho thuộc tính value của <select>, đảm bảo select hiển thị đúng giá trị đang được chọn.
- onChange: React Hook Form cũng cung cấp hàm field.onChange. Khi người dùng chọn một giá trị mới trong <select>, sự kiện onChange của <select> sẽ kích hoạt field.onChange. Hàm này sẽ cập nhật giá trị bên trong React Hook Form, đồng bộ hóa trạng thái form và kích hoạt re-render nếu cần thiết. VD
<select className="form-select" {...field}>
Việc sử dụng ...field là cách ngắn gọn và hiệu quả để truyền tất cả các props value, onChange, onBlur, name, ref từ đối tượng field xuống component <select>. Điều này đảm bảo rằng React Hook Form có thể quản lý hoàn toàn trạng thái và sự kiện của select mà không cần bạn phải xử lý value và onChange một cách thủ công. Nếu bạn cần thực hiện thêm logic khi giá trị thay đổi (ví dụ: cập nhật một state khác hoặc gọi API), bạn có thể bọc onChange của field:
<Controller
name="city"
control={control}
rules={{ required: "Bạn phải chọn thành phố" }}
render={({ field }) => (
<select
className="form-select"
{...field}
onChange={(e) => {
field.onChange(e); // Gọi hàm onChange của field để cập nhật giá trị trong form
// Thêm logic tùy chỉnh của bạn ở đây
console.log("Giá trị thành phố đã thay đổi thành:", e.target.value);
}}
>
<option value="">-- Chọn thành phố --</option>
<option value="hanoi">Hà Nội</option>
<option value="danang">Đà Nẵng</option>
<option value="hcm">TP. HCM</option>
</select>
)}
/>
Workflow của Controller
import { Controller, useForm } from "react-hook-form";
const options = [
{ value: "hanoi", label: "Hà Nội" },
{ value: "danang", label: "Đà Nẵng" },
{ value: "hcm", label: "TP. HCM" },
];
const Kyc = () => {
const {
register,
handleSubmit,
control,
formState: { errors },
} = useForm();
const onSubmit = (data: any) => {
console.log("Selected city:", data.city);
};
return (
<div className="container mt-5">
<h3 className="mb-4">Chọn Thành Phố</h3>
<form onSubmit={handleSubmit(onSubmit)}>
<div className="mb-3">
<label className="form-label">Thành phố</label>
<Controller
name="city"
control={control}
rules={{ required: "Bạn phải chọn thành phố" }}
render={({ field }) => (
<select
className="form-select" {...field}
>
<option value="">-- Chọn thành phố --</option>
<option value="hanoi">Hà Nội</option>
<option value="danang">Đà Nẵng</option>
<option value="hcm">TP. HCM</option>
</select>
)}
/>
{errors.city && (
<div className="text-danger mt-1">{errors.city.message}</div>
)}
</div>
<button type="submit" className="btn btn-primary">
Submit
</button>
</form>
</div>
);
};
export default Kyc;
Trên đây là những khái niệm và ví dụ cơ bản nhất để bạn bắt đầu làm quen với React Hook Form. Hi vọng sẽ giúp ích được bạn trong việc custom validation trên React Hook form
Nhận xét
Đăng nhận xét