I just want the fields in the form to clear after a successful submit, so that they are blank again.
I have a pretty simple form, which you should be able to see below:
export const EmailUsForm = () => {
const emailstate = useAppSelector(state => state.emailstate);
const appstate = useAppSelector(state => state.appstate);
const dispatch = useAppDispatch();
const { control, handleSubmit, reset, formState, formState: { isSubmitSuccessful } } = useForm<Email>({ defaultValues: {senderName: '', senderEmail: '', subject: '', message: ''} as Email });
// in the above, I've also tried:defaultValues: {} as Email
useEffect(() => {
if (formState.isSubmitSuccessful) {
// we get here...
console.log('clearing the form');
dispatch(resetState());
// but this seems to do nothing
reset();
}
// this part works too
console.log('clearing the alert');
setTimeout(() => {
dispatch(clearAlert());
}, 3000)
}, [formState, isSubmitSuccessful, reset]);
const onSubmit: SubmitHandler<Email> = async (data: Email) => {
await dispatch(sendEmail(data));
console.log('onsubmitting -> infoAlert()')
dispatch(infoAlert('email sent'));
}
return (
<Wrapper>
{appstate.showAlert && <Alert />}
<form className='form-wide' onSubmit={handleSubmit(onSubmit)}>
<Controller name="senderName" rules={{ required: 'your name is required' }} control={control} render={({ field, formState: {errors} }) =>
<FormRow {...field} error={errors.senderName?.message} type="input" className="form-input" label="Your Name *" />} />
<Controller name="senderEmail" rules={{ required: {value: true, message: 'email is required'}, pattern: {value: /^(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, message:'email must be valid' }}} control={control} render={({ field, formState: {errors} }) =>
<FormRow {...field} error={errors.senderEmail?.message} type="input" className="form-input" label="Your Email *" />} />
<Controller name="subject" control={control} render={({ field, formState: {errors} }) =>
<FormRow {...field} error={errors.subject?.message} type="input" className="form-input" label="Subject" />} />
<Controller name="message" rules={{ required: 'you must have something to say' }} control={control} render={({ field, formState: {errors} }) =>
<FormRow {...field} error={errors.message?.message} type="input" className="form-input" label="Message *" />} />
<button
type='submit'
className='btn btn-block btn-danger'
>
Submit
</button>
</form>
</Wrapper>
)
}
I have been following the react hook form doc, which assures me that reset() should work, provided:
For controlled components you will need to pass defaultValues to useForm in order to reset the Controller components' value.
When defaultValues is not supplied to reset API, then HTML native reset API will be invoked to restore the form.
Avoid calling reset before useForm's useEffect is invoked, this is because useForm's subscription needs to be ready before reset can send a signal to flush form state update.
It's recommended to reset inside useEffect after submission.
I really think I've followed all of that, can anyone see what's missing here? what I'm not understanding?
UPDATE: OK the form value map is actually resetting - its just that the fields still display the values
There is at least one fix.
As i suggested in the "EDIT" statement, the form's value map is actually updating. If you log.console values()
, you'll see that all the fields are reset()
to their default values. The problem was that the component was not getting updated upon render. I'm a bit surprised about that, because I would have though that with an updated state, the DOM would get updated.
Anyway, by pushing the new value into the component (value={field.value}
) like so:
<FormRow {...field} value={field.value} error={errors.senderName?.message} type="input" className="form-input" label="Your Name *" />} />
the DOM is rendered with the new value.