# React hook form + yup + typescript
==note: xem các file `Register.tsx` và `utils/rules.ts` của `Ecommerce`==
## CÁCH 1 : React hook form
```javascript
yarn add react-hook-form
```
**1. Component input**
```javascript
import type { UseFormRegister, RegisterOptions } from 'react-hook-form'
interface Props {
type: React.HTMLInputTypeAttribute
errorMessage?: string
placeholder?: string
className?: string
name: string
register: UseFormRegister<any>
rules?: any
}
const CustomInput = ({ type, errorMessage, placeholder, className, name, register, rules }: Props) => {
return (
<div className={className}>
<input
type={type}
{...register(name, rules)}
placeholder={placeholder}
className=""
/>
<div className='text-red-500 text-[13px] min-h-[28px]'>{errorMessage}</div>
</div>
)
}
export default CustomInput
```
**2. Use in component**
```javascript
interface FormData {
email: string
password: string
confirmPassword: string
}
const Register = () => {
const {
register,
handleSubmit,
watch,
getValues,
formState: { errors }
} = useForm<FormData>()
const rules = getRules(getValues)
const onSubmit = handleSubmit(
(data) => {
console.log(data)
},
(data) => {
const password = getValues('password')
console.log(password)
}
)
return ( <CustomInput
type='email'
placeholder='Email'
name='email'
register={register}
className=''
errorMessage={errors.email?.message}
rules={rules.email}
/>)
```
**3. File `rules.ts` sử dụng getValues() để validate**
```javascript=
export const getRules = (getValues: any) => ({
email: {
required: {
value: true,
message: 'Vui lòng nhập email'
},
pattern: {
value: /^\S+@\S+\.\S+$/,
message: 'Email không đúng định dạng'
},
maxLength: {
value: 30,
message: 'Email không được dài hơn 30 ký tự'
},
minLength: {
value: 5,
message: 'Email không được ngắn 5 ký tự'
}
},
password: {
required: {
value: true,
message: 'Vui lòng nhập mật khẩu'
},
maxLength: {
value: 30,
message: 'Mật khẩu không được dài hơn 30 ký tự'
},
minLength: {
value: 5,
message: 'Mật khẩu không được ngắn 5 ký tự'
}
},
confirmPassword: {
required: {
value: true,
message: 'Vui lòng xác thực mật khẩu'
},
maxLength: {
value: 30,
message: 'Xác thực mật khẩu không được dài hơn 30 ký tự'
},
minLength: {
value: 5,
message: 'Xác thực mật khẩu không được ngắn 5 ký tự'
},
validate:
typeof getValues === 'function'
? (value:any) => value === getValues('password') || 'Xác thực mật khẩu không giống'
: undefined
}
})
```
## CÁCH 2: NÊN DÙNG react-hook-form + yup
**Install package**
```javascript
npm install @hookform/resolvers yup
yarn add @hookform/resolvers yup
```
**1. File `rule.ts`**
```javascript
export const schema = yup.object({
email: yup
.string()
.required('Vui lòng nhập email')
.email('Email không đúng định dạng')
.min(5, 'Email có ít nhất 5 ký tự')
.max(50, 'Email không thể dài hơn 50 ký tự'),
password: yup
.string()
.required('Vui lòng nhập mật khẩu')
.min(5, 'Mật khẩu có ít nhất 5 ký tự')
.max(50, 'Mật khẩu không thể dài hơn 50 ký tự'),
confirmPassword: yup
.string()
.required('Vui lòng nhập xác thực mật khẩu')
.min(5, 'Xác thực mật khẩu có ít nhất 5 ký tự')
.max(50, 'Xác thực mật khẩu không thể dài hơn 50 ký tự')
.oneOf([yup.ref('password')], 'Xác thực mật khẩu không giống')
})
export const loginSchema = schema.omit(['confirmPassword']); // omit là loại bỏ
export type Schema = yup.InferType<typeof schema>
export type LoginSchema = yup.InferType<typeof loginSchema>
```
**2. CustomInput**
```javascipt
import type { UseFormRegister, RegisterOptions } from 'react-hook-form'
interface Props {
type: React.HTMLInputTypeAttribute
errorMessage?: string
placeholder?: string
className?: string
name: string
register: UseFormRegister<any>
rules?: any
autoComplete?: string | undefined
}
const CustomInput = ({ type, errorMessage, placeholder, className, name, register, rules ,autoComplete}: Props) => {
return (
<div className={className}>
<input
type={type}
{...register(name, rules)}
placeholder={placeholder}
autoComplete={autoComplete}
className='w-full dark:text-white border rounded-md p-3 dark:bg-third-dark outline-none dark:border-primary-dark'
/>
<div className='text-red-500 text-[13px] min-h-[28px]'>{errorMessage}</div>
</div>
)
}
export default CustomInput
```
**3. Component login**
```javascript
import { loginSchema, LoginSchema } from 'src/utils/rule'
import { yupResolver } from '@hookform/resolvers/yup'
const Login = () => {
const {
register,
handleSubmit,
formState: { errors }
} = useForm<LoginSchema>({
resolver: yupResolver(loginSchema)
})
const onSubmit = handleSubmit(
(data) => {
console.log(data)
}
)
return (
<form noValidate onSubmit={onSubmit}>
<CustomInput
type='email'
placeholder='Email'
name='email'
register={register}
className=''
errorMessage={errors.email?.message}
/>
<CustomInput
type='password'
placeholder='Mật khẩu'
name='password'
register={register}
className=''
errorMessage={errors.password?.message}
/>
<PrimaryButton type='submit' content='Đăng nhập' className='w-full mt-2' />
```