はじめに
問題に直面したので、記事にまとめます。
問題
ダイアログを閉じる動作、データを保存する動作、バリデーションエラーを表示する動作を両立できませんでした。
(1) DialogActionTriggerを使う場合
React Hook Formを使用していて、バリデーションが通らないはずなのに、Saveボタンを押せてしまいます。
(学習内容や学習時間を空白にするとエラーになるはずが、押せてしまう)
src/App.tsx
<div>
<label htmlFor="studyContent">学習内容</label>
<input
id="studyContent"
type="text"
{...register('studyContent', {
required: '内容の入力は必須です',
})}
/>
{errors['studyContent'] && (
<p>{errors['studyContent'].message}</p>
)}
</div>
<DialogActionTrigger asChild>
<button type="submit" disabled={true}>Save</button>
</DialogActionTrigger>
ChakraUIのトリガーを使っているため、保存ボタンを押すとダイアログが閉じてしまいます。
再度、登録ボタンを押すとエラーが表示されます。
(2) DialogActionTriggerを使わない場合
src/App.tsx
// <DialogActionTrigger asChild>
<button type="submit" disabled={true}>Save</button>
// </DialogActionTrigger>
Saveボタンを押すとダイアログが閉じずにエラーを表示できます。
しかし、正しく入力すると、登録はできるがダイアログが開いたままになります。
解決方法
watchでstudyHourの状態を監視し、バリデーションが通る場合はDialogActionTriggerを使ってダイアログを閉じ、バリデーションが通らない場合はDialogActionTriggerを外してダイアログを閉じないようにしました。
src/App.tsx
const { register, handleSubmit, formState: { errors }, reset, watch } = useForm<FormValues>();
// 監視用のwatchを定義
const studyContent = watch('studyContent', '');
const studyHour = watch('studyHour', null);
{studyContent && studyHour && studyHour >= 0 ? (
<DialogActionTrigger asChild>
<button type="submit">Save</button>
</DialogActionTrigger>
) : (
<button type="submit">Save</button>
)}
おわりに
終わってみれば複雑ではなさそうですが、解決するのに3、4日かかってしまいました。