react-hook-formのsetErrorではフォームの送信を止められない
Reactでフォームを扱うライブラリといえばreact-hook-form。
このライブラリは送信時に自動でエラーをチェックし、エラーがあれば送信をしないという便利な機能が備わっています。
そして一方でreact-hook-formには、手動でエラーを設定できるsetError
という関数があります。
じゃあ 「これを使ってエラーを設定すればフォームの送信を防げる!」 と思ったら防げなかったので、その理由とreact-hook-formにおける基本的なバリデーション実装の方針をまとめます。
setErrorで送信を防げない理由
そもそもsetError
は送信時のバリデーションとしてデザインされていないから
これが理由のようです。同様の事象で困っているissueがありました。
こちらの回答によると、required
やmin
などのバリデーションをしたいなら、そして送信を防ぎたいならsetError
を使わずに素直にreact-hook-formのregisterオプションの方(あるいはzodなどとの組み合わせ)のバリデーションを使ってね、ということのようです。
公式より引用
This method will force set isValid formState to false, however, it's important to aware isValid will always be derived by the validation result from your input registration rules or schema result.
(DeepL翻訳)
このメソッドはisValid formStateを強制的にfalseに設定しますが、isValidは常に入力登録ルールやスキーマの結果からのバリデーション結果によって導かれることに注意しましょう。
setError
では、エラー状態にしてメッセージを表示することはできるが、送信時のバリデーションとしては力を発揮できないということですね。
いつsetErrorを使うのか
ではいつsetError
を使えばいいのか、setError
の存在意義は何なのかというと、主に非同期なバリデーションでその真の力を発揮します。
例えば、次のような簡単な登録フォームを考えてみましょう。
- ユーザー名 (システム上でユニーク)
- パスワード
というフォームが並んでいたとして、ひとつめのユーザー名を入力し、パスワードフォームにフォーカスを移したとします。
このときユーザー名フォームのonBlur
が発火しますが、ここにユーザー名がユニークかどうかをサーバーサイドでチェックする処理を挟みます。
そしてチェックの結果がエラーであればsetError
でエラー状態にすることで、ユーザーはパスワードの入力中にユーザー名フォームのエラーに気付ける、という感じです。
プログラムのイメージは次のようになるでしょうか。
<input
{...register('username')}
onBlur={(e) => {
// 非同期のバリデーション処理
if (!data.isUnique) {
setError('username', {
type: 'manual',
message: 'このユーザー名はすでに使われています'
});
}
}}
/>
以上です。react-hook-formの機能のすみ分けやライブラリの意図を汲み取ることができた気がして勉強になりました。
Discussion