# 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' /> ```