Tìm hiểu nhanh về React Hook Form

Phùng Hùng

Phùng Hùng

Teacher and Programmer

Cài đặt

npm install react-hook-form

Ví dụ

Đoạn mã sau mô tả cách sử dụng cơ bản của React Hook Form:

import React from 'react';
import { useForm } from 'react-hook-form';
const App = () => {
const { register, handleSubmit, watch, errors } = useForm();
const onSubmit = data => console.log(data);
console.log(watch('example')); // theo dõi giá trị trường bằng cách truyền tên của nó
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input name="example" defaultValue="test" ref={register} />
<input name="exampleRequired" ref={register({ required: true })} />
{errors.exampleRequired && <span>This field is required</span>}
<input type="submit" />
</form>
);
};
export default App;

Phương thức register

Cho phép bạn đăng ký một input với React Hook Form, chỉ khi một trường được đăng ký nó mới được xác thực và submit.

Quy tắc đặt tên trường

Khi sử dụng register, các trường bắt buộc phải đặt tên, các tên phải là duy nhất. Cách đặt tên quy định định dạng dữ liệu do trường này trả về:

Tên trườngDữ liệu
name="firstName"{ firstName: 'value' }
name="firstName[0]"{ firstName: [ 'value] }
name="name.firstName"{ name: { firstName: 'value' } }
name="name.firstName[0]{ name: { firstName: [ 'value' ] } }

Xác thực dữ liệu của trường

register hỗ trợ các hình thức xác định đơn giản có sẵn trong HTML Form:

// Trường bắt buộc
<input name="test" ref={register({
required: true
})} />
// Chuỗi có chiều dài tối đa là 12, tối thiểu là 6
<input name="test" ref={register({
minLenght: 6,
maxLenght: 12,
})} />
// Số có giá trị nhỏ nhất là 3, lớn nhất là 10
<input name="test" ref={register({
min: 3,
max: 10
})} />
// Match với regex pattern
<input name="test" ref={register({
pattern: /[A-Za-z]{3}/
})} />

Ngoài ra bạn cũng có thể tự viết một hàm hoặc đối tượng chứa nhiều hàm xác thực rồi truyền cho validate:

// hàm xác thực, yêu cầu giá trị
// trường phải là '1'
<input name="test" ref={register({
validate: value => value === '1'
})} />
// Đối tượng chứa các hàm xác thực
// yêu cầu giá trị có dạng số
// lớn hơn 0 và nhỏ hơn 10
<input name="test" ref={register({
validate: {
positive: value => parseInt(value, 10) > 0,
lessThanTen: value => parseInt(value, 10) < 10,
}
})} />
// Hàm xác thực có thể thực hiện
// bất đồng bộ
<input name="test" ref={register({
validate: aysnc value => await fetch(url)
})} />

Phương thức handleSubmit

Đối số của phương thức này là một hàm callback, hàm callback được tự động truyền vào dữ liệu của cả form cũng như sự kiện event. Bạn cũng có thể truyền vào một callback thứ hai để xử lý lỗi.

handleSubmit trả về một hàm, khi gọi hàm này các callback được chạy. Sở dĩ handleSubmit trả về hàm, vì để ta có thể truyền nó vào các thuộc tính on... của component.

import React from 'react';
import { useForm } from 'react-hook-form';
const App = () => {
const { register, handleSubmit } = useForm();
const onSubmit = (data, e) => console.log(data, e);
const onError = (errors, e) => console.log(errors, e);
return (
<form onSubmit={handleSubmit(onSubmit, onError)}>
<input name="firstName" ref={register} />
<input name="lastName" ref={register} />
<button type="submit">Submit</button>
</form>
);
};

handleSubmit chấp nhận các các hàm async:

handleSubmit(async data => await fetchAPI(data));

Phương thức watch

Nó theo dõi một trường và trả về giá trị của trường mỗi khi có thay đổi.

Khi không định nghĩa giá trị mặc định của trường qua defaultInput, watch ban đầu sẽ trả về undefined bởi nó được gọi trước register.

Xử lý lỗi xác thực với errors

Đối tượng errors được dùng để kiểm tra xem có lỗi xảy ra với trường nào đó hay không.

import React from 'react';
import { useForm } from 'react-hook-form';
export default function App() {
const { register, errors, handleSubmit } = useForm();
return (
<form onSubmit={handleSubmit(onSubmit)}>
<Input name="firstName" ref={register({ required: true })} />
{errors.firstName && 'First name is required'}
<Input name="lastName" ref={register({ required: true })} />
{errors.lastName && 'Last name is required'}
<input type="submit" />
</form>
);
}

errors cũng chứa cả những thông báo lỗi, chẳng hạn:

<form onSubmit={handleSubmit(onSubmit)}>
<input type="text" name="firstName" ref={register} />
<p>{errors.firstName?.message}</p>
<input type="text" name="age" ref={register} />
<p>{errors.age?.message}</p>
<input type="submit" />
</form>

Chú ý rằng ?. là toán tử optional chaining cho phép chỉ đọc thuộc tính của một đối tượng khi nó không null hoặc undefined.

Kiểu lỗi được chứa trong thuộc tính type:

<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="name">Name</label>
<input
type="text"
id="name"
ref={register({ required: true, maxLength: 30 })}
/>
{errors.name && errors.name.type === 'required' && (
<span>This is required</span>
)}
{errors.name && errors.name.type === 'maxLength' && (
<span>Max length exceeded</span>
)}
<input type="submit" />
</form>

Schema Validation với Yup

Trước tiên cài Yup và Yup Resolvers

npm install @hookform/resolvers yup

Sau đó chuẩn bị schema và truyền vào useForm:

import React from 'react';
import { useForm } from 'react-hook-form';
import { yupResolver } from '@hookform/resolvers';
import * as yup from 'yup';
const schema = yup.object().shape({
firstName: yup.string().required(),
age: yup.number().positive().integer().required(),
});
const App = () => {
const { register, handleSubmit, errors } = useForm({
resolver: yupResolver(schema);
});
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<input type="text" name="firstName" ref={register} />
<p>{errors.firstName?.message}</p>
<input type="text" name="age" ref={register}>
<p>{errors.age?.message}</p>
<input type="submit" />
</form>
);
}
export default App;

Khi đã sử dụng Schema Validation bạn không cần truyền quy tắc xác thực vào register nữa.