😀

React Hook Form + zodで数値型のselectの空文字対応

2022/10/06に公開1

React Hook Form + zodで実装しているselectで数値型を指定すると、未選択時の空文字でエラーが出てしまうので対処法。

たとえば、zodで数値を指定して、optionのvalueに数値が入っている場合はvalueAsNumberを指定することで文字列型を数値に変換してくれて問題なく動作します。

item: z.number()
<select ref={register('item', { valueAsNumber: true })}>
  <option value="1">項目1</option>
  <option value="2">項目2</option>
</selet>

selectの先頭に未選択時の項目を入れる

これまではすべてのoptionにvalueが入っていたところに下記のような未選択状態のoptionを入れるとします。

<select ref={register('item', { valueAsNumber: true })}>
  <option value="">選択してください</option>
  <option value="1">項目1</option>
  <option value="2">項目2</option>
</selet>

空文字のvalueのoptionが追加されたことにより、未選択状態だとzodで指定しているnumber型のエラーが出るようになってしまいます。
z.number().optional()でいけるかと思ったのですが、空文字はあくまでもstring型のためエラーに・・。

そこでvalueAsNumberの指定を外してsetValueAsで値を改変するようにします。
setValueAsはvalueAsNumberが指定されていると動作しないため注意。

const selectRef = register('item', {
  setValueAs: (v) => (v === '' ? undefined : parseInt(v, 10)),
})
<select ref={selectRef}>
  <option value="1">項目1</option>
  <option value="2">項目2</option>
</selet>

参考

今回は下記を参考にしました。
リンク先ではinputに対してsetValueAsを使用していますが、selectでも同様の対応が可能です。

https://github.com/react-hook-form/react-hook-form/discussions/6980

Discussion

nap5nap5

この指定はそのままにして

{ valueAsNumber: true }

未選択の状態をid:-1としてワークアラウンドしてみました。
さらにlookUpも追加してみました。

https://codesandbox.io/p/sandbox/lucid-surf-7mx50p?file=%2Fsrc%2Ffeatures%2Fselect-first-item-not-selected%2Fcomponents%2FForm.tsx&selection=[{"endColumn"%3A11%2C"endLineNumber"%3A23%2C"startColumn"%3A11%2C"startLineNumber"%3A23}]

/select-first-item-not-selectedがデモページになります。

簡単ですが、以上です。