😃

useFormのmode復習とtriggerについて

2025/01/30に公開

useFormのmode:"onBlur"を利用したら、errorsにオブジェクトが格納されない

複数のコンポーネントをまとめた情報入力画面で、必須選択項目にバリデーションチェックを行い、未選択の場合はerrorsに格納するようにした。情報入力画面下部の「次へ」ボタンを押すと未選択の項目がフォーカスされ、赤枠で表示される予定。しかし1回目で「次へ」ボタンを押すとフォーカスが実行されない。別コンポーネントの選択項目を選択し直すなどすると、フォーカスが実行される。確認してみると、フォーカスが実行されないときはerrorsにオブジェクトが格納されていないことがわかった。(1回「次へ」ボタンを押して、選択し直すと2回目以降はerrorsに格納される。)

オブジェクト定義はこんな感じ

const methods = useForm({
    defaultValues: {
      workerCd: state.report.workerCd,
      workDateForm: state.report.workDateForm,
      workDay: state.report.workDay
        ? state.report.workDay
        : formatDateToString(new Date()),
      workTime: state.report.workTime,
    },
    // フォーカスが外れたタイミングでバリデーションをチェック
    mode: "onBlur",
    // Submit後のバリデーション
    reValidateMode: "onBlur",
    // 入力エラー時エラー先頭項目にフォーカスがあたらないため手動でフォーカス設定
    shouldFocusError: false,
  });

ここで一旦useForm(mode)の復習。

このサイト満遍なくreact-hook把握できる

useFormを使うとフォームの状態管理やバリデーションルールが柔軟かつ簡単に設定できる。
modeは初回フォーム送信時(handleSubmit)のバリデーションの実行タイミングを細かく設定することができる。

・onSubmit / 送信時 (初期値)
・onBlur /  対象の不フィールドからフォーカスを外したタイミング
・onChange / 入力項目が変更されたとき
・all / onBlur, onChange時

最初、modeの"onBlur"が原因かと思ってその他のプロパティ(onChange, all...)も試してみたけど改善しなかった。だがタイミングの問題であることは明らか。

そこで、次へボタン押下タイミング(handleOnClickNext関数内)の最初にtriggerを設定してみた。

triggerとは

フォームやinputのバリデーションを手動で発動させることができる関数。入力が他の入力項目と依存関係にある項目のバリデーションチェックにも役に立つそう。

引数の取り方と意味はこんな感じ
・未定義:全てのフィールドでバリデーションをトリガー
trigger()
・String:nameの指定によって特定の項目の単一の値のバリデーションをトリガー
trigger("yourDetails.firstName")
・String[]:nameの指定によって複数の項目のバリデーションをトリガー
trigger(["yourDetails.lastName"])
・boolean(shouldFocus):エラー設定時に入力にフォーカスするかどうかを決められる
trigger('name', { shouldFocus: true })

こんな感じ

const handleOnClickNext = () => {
    // バリデーションエラー時にフォーカスされない場合があるため手動のトリガーを設定
    trigger();
    setPushedNextButton(true);
}

今回は複数コンポーネントにわたる入力項目すべてに対してバリデーションをトリガーしたかったので、allで対応。公式ドキュメントでは場所的にbutton, onClickでtriggerを設定することが推奨されてるのかな??

 return (
    <form>
      <input {...register("firstName", { required: true })} />
      <input {...register("lastName", { required: true })} />
      <button
        type="button"
        onClick={() => {
          trigger()
        }}
      >
        Trigger All
      </button>
    </form>
  )

何はともあれ、しっかり1回目でerrorsに格納されましたとさ。

Discussion