【React.js】关于React Hook Form
React Hook Form (中文翻译):响应式钩子表单
React Hook Form的优点是什么?
通过将表单实现为“非受控组件”而不是“受控组件”,可以实现高性能,即防止不必要的重新渲染和实现表单。
请将以下内容用中文进行释义:↓
为了将其作为非控制组件进行处理,需要使用forwardRef。
由于React Hook Form需要通过非受控组件的ref直接访问表单元素的值、焦点、错误状态等,故必须这样做。
forwardRef 是什么意思?
forwardRefはReactのビルトイン関数
この関数を使用することで、親コンポーネントから渡されるrefを子コンポーネントの内部のDOM要素やクラスコンポーネントインスタンスに直接関連付けることができる
forwardRefを使用すると、第二の引数としてrefを受け取る新しいコンポーネントが作成される
实施方式
使用forwardRef来实现表单
export const Input = ⭐️forwardRef<HTMLInputElement, Props>(
(
{
onChange,
placeholder,
disabled,
errorText,
unit,
unitSize = 1,
defaultValue = '',
name,
},
// 関数の第二引数として親から渡されるref。このrefでinputの監視を行っている
forwardedRef ⭐️
) => {
const { value, setInputValue } = useInputValue(onChange, defaultValue)
return (
<Input.Wrapper
error={errorText}
classNames={{
error: 'text-red-500 text-xs mt-2 mb-4',
}}
>
<Input
classNames={{
input: ``
}}
// onChange: react-hook-formのregister関数が反応する
onChange={(e) => {
setInputValue(e)
}}
placeholder={placeholder}
disabled={disabled}
ref={forwardedRef} // ⭐️
value={value}
// error: react-hook-formのerrorsオブジェクトを使用してエラー情報を取得できる
error={errorText} // ⭐️
// name: react-hook-formでデータを識別するためのキーとして使用される
name={name} // ⭐️
rightSection={unit && <Unit>{unit}</Unit>}
/>
</Input.Wrapper>
)
}
)
Input.displayName = 'Input' ⭐️ // コンポーネントの名前を明示的に設定
使用所创建的输入
const {
handleSubmit,
register,
watch,
resetFormAndErrors,
control,
isSubmitting,
errors,
} = useUserForm(initialValue)
<form
onSubmit={handleSubmit(handleSubmitForm, onClose)}
className='pt-2'
>
<Input
placeholder={'Mr. Bean'}
errorText={errors.user.tel?.message}
{...register('user.name')}
/>
<InputNumber
placeholder={'01988882222'}
errorText={errors.user.tel?.message}
{...register('user.tel')}
/>
<Input
placeholder={'yyyy@xxx.co.jp'}
errorText={errors.user.email?.message}
{...register('user.email')}
/>
<Button
onClick={onClose}
disabled={isSubmitting}
>
閉じる
</Button>
<Button
type={'submit'}
disabled={isSubmitting}
>
保存する
</Button>
</form>
3. 配置模式,使用 useForm 进行实现
const TEL_NUMBER_LENGTH = 11
const EMAIL_PATTERN_REGEX = /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/
// emailアドレスが、期待される形式であるかどうかを確認するための関数
// email: inputに入力されたemailアドレス。
// emailアドレスが期待される形式であればtrueを、そうでなければfalseを返す。
const validateEmail = (email: string) => {
if (email === '') {
return true
}
return EMAIL_PATTERN_REGEX.test(email)
}
// 電話番号が指定した通りの桁数が入力されているかどうかを確認するための関数
// tel: inputに入力された電話番号。
// 指定した通りの桁数が入力されていればtrueを、そうでなければfalseを返す。
const validateTelNumber = (tel: string) => {
if (tel === '') {
return true
}
return tel.length === TEL_NUMBER_LENGTH
}
// ⭐️ ここベースのSchemaが完成
const schema = z.object({
user: z.object({
name: z.string(), // string型のみ許容
email: z.string().refine(validateEmail, {
message: '有効なメールアドレスを入力してください。',
}), // 自身でカスタムしたvalidationのルールに沿って許容
tel: z.string().refine(validateTelNumber, {
message: '電話番号の桁数が適切ではありません。',
}), // 自身でカスタムしたvalidationのルールに沿って許容
})
});
// カスタム hook この中でuseFormを使用し、処理を定義
export const useUserForm = (initialValue: FormValues) => {
const {
handleSubmit,
register,
formState: { isSubmitting, errors },
resetField,
} = useForm<SchemaType>({
mode: 'onSubmit', // submitの時にvalidation処理を発動させるための設定
reValidateMode: 'onSubmit', // 2回目以降、onSubmitの時にvalidationを発動させるという設定
resolver: zodResolver(schema), // zodResolverを定義
defaultValues: { // inputに初期値を定義させる
user: {
name: initialValue.user.name,
email: initialValue.user.email,
tel: initialValue.user.tel,
},
},
})
// 保存ボタンがクリックされた時に呼び出され、フォームデータの送信を行う関数
const onSubmitForm = (
handleSubmitForm: ModalProps['handleSubmitForm'],
onClose: () => void
) => {
// フォームデータの送信とresetField、モーダルを閉じる処理を行う関数。
const handleSend: SubmitHandler<SchemaType> = async (
values
): Promise<void> => {
await handleSubmitForm(values)
resetFormAndErrors()
onClose()
}
return handleSubmit(handleSend)
}
// user情報の入力情報をリセットする関数。
const resetFormAndErrors = () => {
resetField('user')
}
return {
handleSubmit: onSubmitForm,
register,
resetFormAndErrors,
isSubmitting,
errors,
}
}
(1) 创建模式
是否只允许输入文字,是否存在字符数量限制?是否有指定只能输入电子邮件等的表单设置的实现?
const TEL_NUMBER_LENGTH = 11
const EMAIL_PATTERN_REGEX = /^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/
// emailアドレスが、期待される形式であるかどうかを確認するための関数
// email: inputに入力されたemailアドレス。
// emailアドレスが期待される形式であればtrueを、そうでなければfalseを返す。
const validateEmail = (email: string) => {
if (email === '') {
return true
}
return EMAIL_PATTERN_REGEX.test(email)
}
// 電話番号が指定した通りの桁数が入力されているかどうかを確認するための関数
// tel: inputに入力された電話番号。
// 指定した通りの桁数が入力されていればtrueを、そうでなければfalseを返す。
const validateTelNumber = (tel: string) => {
if (tel === '') {
return true
}
return tel.length === TEL_NUMBER_LENGTH
}
// ⭐️ ここベースのSchemaが完成
const schema = z.object({
user: z.object({
name: z.string(), // string型のみ許容
email: z.string().refine(validateEmail, {
message: '有効なメールアドレスを入力してください。',
}), // 自身でカスタムしたvalidationのルールに沿って許容
tel: z.string().refine(validateTelNumber, {
message: '電話番号の桁数が適切ではありません。',
}), // 自身でカスタムしたvalidationのルールに沿って許容
})
});
使用 useForm 创建一个自定义的 hook。
// カスタム hook この中でuseFormを使用し、処理を定義
export const useUserForm = (initialValue: FormValues) => {
const {
handleSubmit, // 送信する関数
register, // { name, ref, onChange, onBlur }の要素を持つオブジェクト
formState: { isSubmitting, errors }, // formの状態
resetField, // formの状態をリセットする関数
} = useForm<SchemaType>({
mode: 'onSubmit', // submitの時にvalidation処理を発動させるための設定
reValidateMode: 'onSubmit', // 2回目以降、onSubmitの時にvalidationを発動させるという設定
resolver: zodResolver(schema), // zodResolverを定義
defaultValues: { // inputに初期値を定義させる
user: {
name: initialValue.user.name,
email: initialValue.user.email,
tel: initialValue.user.tel,
},
},
})
// 保存ボタンがクリックされた時に呼び出され、フォームデータの送信を行う関数
const onSubmitForm = (
handleSubmitForm: ModalProps['handleSubmitForm'],
onClose: () => void
) => {
// フォームデータの送信とresetField、モーダルを閉じる処理を行う関数。
const handleSend: SubmitHandler<SchemaType> = async (
values
): Promise<void> => {
await handleSubmitForm(values)
resetFormAndErrors()
onClose()
}
return handleSubmit(handleSend)
}
// user情報の入力情報をリセットする関数。
const resetFormAndErrors = () => {
resetField('user')
}
return {
handleSubmit: onSubmitForm,
register,
resetFormAndErrors,
isSubmitting,
errors,
}
}
使用 useForm 的方法定义
const { formを操る処理 } = useForm<監視したい値のschemaの型>({ 初期値や、どの操作の時に処理するかなどの設定 })
总结
使用React Hook Form这个库可以充分利用非受控组件的优点,实现高性能的表单。要使用这个库,需要以下内容:
• 实现forwardRef
• 定义适当的验证模式
• 创建自定义hook
请先参阅以下资料: