うまく動かないとき
よくつまずく症状と、その原因、直し方をまとめています。
このページの内容
parseFormが「FormDataに無い」というエラーを投げる
原因
スキーマにある入力欄の名前が、送信されたFormDataにありません。多くの場合、その入力欄にinputを展開し忘れているか、条件によって入力欄を描いていません。
直し方
すべての入力欄にinputを展開し、.optional()の付いたオブジェクトの中の入力欄も必ず描きます。何も選ばなければ値を送らないラジオボタンや<select>、チェックボックスは、このエラーの対象外です。
.optional()を付けたのに、空欄のままだと通らない
原因
空のテキスト欄は、値が無いのではなく""を送ります。.optional()は値が無い場合を許すだけなので、.min(1)のような検証は""に対してそのまま働きます。
直し方
空欄を許したいときは、z.union([z.literal(''), z.string().min(3)])のように""を受け付けるスキーマを書きます。ただしこの場合、.min(3)はどちらの枝を確かめるか決まらないため、ブラウザでは確かめずdroppedに載ります。
zod/miniで書いたら、文言が「Invalid input」になる
原因
zod/miniは、バンドルを小さく保つために、文言の辞書を自動では読み込みません。辞書が無いと、どのエラーもInvalid inputになります。
直し方
サーバーで最初に読み込まれるモジュールでz.config(z.locales.ja())のように辞書を読み込むか、スキーマの検証ごとに文言を書きます。
送信に失敗したあと、ラジオボタンの選択が戻らない
原因
自分で書いたラジオボタンにinputをそのまま展開しています。送信のあとはinputに前回の値がdefaultValueとして入り、各ラジオボタンのvalueとぶつかります。
直し方
inputからはnameとrequiredだけを渡し、state.valuesを見て選択肢ごとにdefaultCheckedを決めます。@k8ordo/uiのRadioとRadioCardなら、そのまま展開できます。
同じ失敗を返すと、2回目はフォーカスが移らない
原因
useFormは、返ってきたstateを中身とtokenで見分けます。自分で組み立てたstateに新しいtokenが無いと、同じ内容の2回目の失敗は前と同じ返事とみなされます。
直し方
parseFormが返したstateを広げて使うか、自分で組み立てるときは毎回新しいtokenを入れます。
隠れたステップのエラーにフォーカスが移らない
原因
hiddenの付いたステップの中の入力欄は、フォーカスを受け取れません。
直し方
新しいstateが届いたら、エラーのあるステップへ描画の中で切り替えます。詳しくは「複数ステップのフォーム」を見てください。
stringboolのチェックボックスが「on」を送る
原因
@k8ordo/uiのCheckboxには、展開したvalueが届きません。そのため、ブラウザの既定のonが送られます。
直し方
z.stringbool()の欄は、素の<input {...field.input} />で描きます。
NumberFieldの範囲のエラーだけ、文言がzodと違う
原因
NumberFieldはtype="text"で描くので、ブラウザはminとmaxを確かめません。範囲の外の値はNumberFieldが自分で知らせ、その文言は@k8ordo/uiの辞書のものです。
直し方
文言をzodにそろえたいときは、TextFieldにtype="number"のまま展開します。ブラウザが範囲を確かめ、useFormがzodの文言を出します。