【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

请先参阅以下资料:

 

广告
将在 10 秒后关闭
bannerAds