reactjsreact-hook-form

react-hook-forms reset() not working after successful submit of controlled form


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:

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

enter image description here


Solution

  • 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.