Chuyển đến nội dung chính

React Hook Form với Controller

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

    flowchart TD Start(["🧑‍💻 Người dùng tương tác"]) --> Input["<select> thay đổi giá trị"] Input --> FieldOnChange["field.onChange được gọi"] FieldOnChange --> FormState["🧠 Cập nhật form state (qua control)"] FormState --> Validate["✅ Kiểm tra rules nếu có"] Validate -->|OK| SubmitBtn["🖱️ Click nút Submit"] SubmitBtn --> handleSubmit["📤 Gọi handleSubmit"] handleSubmit --> DataObject["📦 Dữ liệu gửi đi: data.city"] %% Cấu trúc liên kết các thành phần subgraph "Controller (<Controller />)" controlRef["control (từ useForm)"] ruleConfig["rules: required, min, max..."] renderFn["render={({ field }) => ...}"] renderFn --> fieldObj["field: name, value, onChange, ref..."] end %% Kết nối giữa Controller và Input fieldObj -->|"...field"| Input %% Điều khiển qua control controlRef --> FormState ruleConfig --> Validate
    Dưới đây là code ví dụ chọn và validate City, kết quả xuất ra console log
    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

Bài đăng phổ biến từ blog này

[ASP.NET MVC] Authentication và Authorize

Một trong những vấn đề bảo mật cơ bản nhất là đảm bảo những người dùng hợp lệ truy cập vào hệ thống. ASP.NET đưa ra 2 khái niệm: Authentication và Authorize Authentication xác nhận bạn là ai. Ví dụ: Bạn có thể đăng nhập vào hệ thống bằng username và password hoặc bằng ssh. Authorization xác nhận những gì bạn có thể làm. Ví dụ: Bạn được phép truy cập vào website, đăng thông tin lên diễn đàn nhưng bạn không được phép truy cập vào trang mod và admin.

ASP.NET MVC: Cơ bản về Validation

Validation (chứng thực) là một tính năng quan trọng trong ASP.NET MVC và được phát triển trong một thời gian dài. Validation vắng mặt trong phiên bản đầu tiên của asp.net mvc và thật khó để tích hợp 1 framework validation của một bên thứ 3 vì không có khả năng mở rộng. ASP.NET MVC2 đã hỗ trợ framework validation do Microsoft phát triển, tên là Data Annotations. Và trong phiên bản 3, framework validation đã hỗ trợ tốt hơn việc xác thực phía máy khách, và đây là một xu hướng của việc phát triển ứng dụng web ngày nay.

Tổng hợp một số kiến thức lập trình về Amibroker

Giới thiệu về Amibroker Amibroker theo developer Tomasz Janeczko được xây dựng dựa trên ngôn ngữ C. Vì vậy bộ code Amibroker Formula Language sử dụng có syntax khá tương đồng với C, ví dụ như câu lệnh #include để import hay cách gói các object, hàm trong các block {} và kết thúc câu lệnh bằng dấu “;”. AFL trong Amibroker là ngôn ngữ xử lý mảng (an array processing language). Nó hoạt động dựa trên các mảng (các dòng/vector) số liệu, khá giống với cách hoạt động của spreadsheet trên excel.