2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React Hook FormのsetValueAsって便利だと思った話

Posted at

元々React Hook Formを使ってフォームを管理していたのですが、
普段の癖でEnterキーを押して入力を確定させていたときに、
「あれ、Enterで確定すると値が反映されていない?」と気づく場面がありました。

調べてみたところ、次のような問題が発生していました。

  • 入力値をフォーマットしてsetValueする処理をonBlurイベントのタイミングで行っていた
  • フォームから離れずにEnterを押した場合、onBlurが発生せず、値が更新されなかったり、計算が思うようにいかなかったりすることがあった

今回私はこの問題をsetValueAsを用いることで解決しました。

setValueAsとは

  • フォームの値のバリデーション前に実行される関数
  • テキスト入力が可能な値でのみ使用できる
  • 初期値(defaultValuedefaultValues)に対しては適用されず無視される

どのタイミングで処理されるか

先ほどの説明通り、setValueAsはフォームの値がバリデーションにかかる前に実行される関数です。

一般的に、またReact Hook Formにおいても、バリデーションはフォーム送信前に実行されます。

便利ポイント

  • onBlurイベントに依存せず、Enter押下によるsubmit前にも値の整形を行える
  • 入力イベントの取りこぼしを気にせず、フォームの値を一元的に管理できる
  • 表示用のフォーマットと内部で扱う値を分離して管理しやすくなる

今回の機能ではユーザーが時間を入力して、フォーカスが外れた際に値を整形をし、
その後にsetValueでフォームに値をセットするようにしていました。

(例)
入力中  =>  フォーカスが外れた後 
0930   =>  09:30

この機能では必ずonBlurイベントが発生することを前提に作られていました。

  const { setValue } = useFormDefault(methods);

  useEffect(() => {
    setValue(startAtName, toTimeString(startAt));
  }, [startAt]);

  const handleChangeStartAt = (e: ChangeEvent<HTMLInputElement>) => {
    setStartAt(parseTime(e.target.value));
  };

~~~~~~~
 registerOptions={{
                onBlur: handleChangeStartAt,
               }}

しかし、onBlurはフォーカスが外れないとイベントが発生しないため、
今回のように直接Enterボタンを押してsubmitされるとイベントが発生しません。
そうすると値のフォーマットができないだけでなく、
そもそも値をフォームにセットすることができないという問題が発生しました。

setValueAsは、onChangeやsubmitなどを通じて、React Hook Formが取得した値を変換し、それを内部的にフォームの値として登録する処理です。

registerOptions={{
                setValueAs(value: string) {
                  return toPostTimeString(parseTime(value));
                },
              }}

これを使うことで入力された値が変化したタイミングでフォーマットを行う処理を動かすことができるため、そのままEnterを押してsubmitされたとしても、その時にはフォーマットされた値をセットすることができます。

ただ変換を行うだけでなく、フォームに渡ってきた値で計算をしたいなど、何か処理を実施したい場合についても、このタイミングで処理を実行することで行うことができます。

registerOptions={{
                setValueAs(value: string) {
                  onValueNormalize(); //ここで計算処理なども実行できる
                  if (!value) return "";
                  return toPostTimeString(parseTime(value));
                },
              }}

注意点

便利な関数ではありますが、公式の説明にOnly applies to text input.とあるように、この関数が適用されるのはテキスト入力が可能な場合のみです。

つまりラジオボタンの制御などを行いたい場合は、別の方法を検討する必要があります。

まとめ

今回はsetValueAsについて紹介してみました。
同じようにonBlur依存の処理で悩んでいる場合は、
選択肢のひとつとしてsetValueAsを検討してみるといいかもしれません。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?