
React Hook Form:数字で始まるnameはNG
この記事は3分で読めます
こんにちは。今日も記事をご覧いただきありがとうございます。
React Hook Form で、ライブラリを更新したらフォームのバリデーションエラーが急に表示されなくなりました。
原因は name を数字で始めていたことでした。備忘録として残しておきます。
起きたこと
設問ごとに入力欄を並べるフォームで、name に設問の番号をそのまま使っていました。
<Controller
name={`${i}.value`} // 数字で始まる name
control={control}
render={({ field }) => <input {...field} />}
/>
これまでは問題なく動いていましたが、@hookform/resolvers を v5.9.0 から v5.9.1 に上げたところ、エラーメッセージが入力欄に表示されなくなりました。
原因
そもそも数字で始まる name は使えない
公式ドキュメントの register のルールに、数字で始まる名前は使えないと書かれています。最近変わったルールではなく、v7(2021年)からあるものです。
React Hook Form は name を「.」区切りのパスとして扱い、数字だけの部分は配列の番号と解釈します。
そのため 0.value は、意図していた answers[0].value ではなく、ルート直下の "0" というキーを指してしまいます。
useForm<FormValues> で型を付けていれば、本来は型エラーで気づけるケースです。
それでも今まで動いていた理由
v5.9.1 で、エラーのパスを整える escapeBrackets という関数が修正されました(Issue #875)。
- v5.9.0:「[」と「]」をただ消す → [0].value は 0.value になる
- v5.9.1:[数字] を .数字 に変えてから消す → [0].value は .0.value になる
v5.9.0 では、変換後のパスが数字で始まる name と偶然一致していたため、エラーが表示されていました。
修正によって一致しなくなり、表示されなくなったというわけです。
対処法
数字で始まらないパスにします。今回は配列で持つ形にしました。
type FormValues = {
answers: { id: number; value: string }[];
};
const { control } = useForm<FormValues>({
defaultValues: {
answers: questions.map((q) => ({ id: q.id, value: "" })),
},
});
{questions.map((q, i) => (
<Controller
key={q.id}
name={`answers.${i}.value`}
control={control}
render={({ field }) => <input {...field} />}
/>
))}
ポイントは、ID を値として持たせて、パスの番号には「何番目か」を使うことです。
answers.${q.id}.value のように ID を番号にすると、ID が 100 のとき長さ101の配列ができてしまうので注意が必要です。
配列にしなくても、q_1 のように先頭に文字を付けるだけでも解決します。
参考
記事を最後まで読んでいただきありがとうございました。また次の記事でお会いしましょう。
