Formik: How to reset form after submit?

Created on 20 Feb 2018  路  30Comments  路  Source: formium/formik

Bug, Feature, or Question?

Question: How to reset form after submit?

Current Behavior

Once the form is submitted, form is not clearing.

Desired Behavior

Form should clear after submit.

Suggested Solutions

Info

I'm using enableReinitialize={true} to clear the form and it's not working. However handleReset is working but I want this function when I submit the form.

  • Formik Version: 0.11.10
  • OS: Win 10
  • Node Version: 8.9.4
  • Package Manager and version:
Question

Most helpful comment

@ivanasetiawan I was able to get it to work by supplying the value prop to my input components. I had to pass an empty object into the resetForm function as well or values within Formik would be null.


const onSubmit = async (values, {setSubmitting, setErrors, setStatus, resetForm}) => {
  try {
    await auth.passwordUpdate(values.oldPassword, values.passwordOne)
    resetForm({})
    setStatus({success: true})
  } catch (error) {
    setStatus({success: false})
    setSubmitting(false)
    setErrors({submit: error.message})
  }
}

const PasswordChangeForm = () =>
  <Formik
    validationSchema={validationSchema}
    onSubmit={onSubmit}>
    {({errors, handleSubmit, handleChange, isSubmitting, isValid, status, values}) =>
      <Form
        loading={isSubmitting}
        success={!!status && !!status.success}
        error={!!errors.submit}
        onSubmit={handleSubmit}>

        <FormInput
          value={values.oldPassword || ''}
          onChange={handleChange}
          type='password'
          placeholder='Old Password'
          name='oldPassword'
        />

        <FormInput
          value={values.passwordOne || ''}
          onChange={handleChange}
          type='password'
          placeholder='New Password'
          name='passwordOne'
        />

        <FormInput
          value={values.passwordTwo || ''}
          onChange={handleChange}
          type='password'
          placeholder='Confirm New Password'
          name='passwordTwo'
        />

        <Button disabled={!isValid} type='submit'>
          Reset My Password
        </Button>

      </Form>
    }
  </Formik>

All 30 comments

You can call resetForm from your handleSubmit / onSubmit function

@jaredpalmer Is it possible to call resetForm not onSubmit function? I tried to clear the persistent value but unable to do it.. I have been googling but couldn't find any example :( If possible, could you share an example?

@ivanasetiawan I was able to get it to work by supplying the value prop to my input components. I had to pass an empty object into the resetForm function as well or values within Formik would be null.


const onSubmit = async (values, {setSubmitting, setErrors, setStatus, resetForm}) => {
  try {
    await auth.passwordUpdate(values.oldPassword, values.passwordOne)
    resetForm({})
    setStatus({success: true})
  } catch (error) {
    setStatus({success: false})
    setSubmitting(false)
    setErrors({submit: error.message})
  }
}

const PasswordChangeForm = () =>
  <Formik
    validationSchema={validationSchema}
    onSubmit={onSubmit}>
    {({errors, handleSubmit, handleChange, isSubmitting, isValid, status, values}) =>
      <Form
        loading={isSubmitting}
        success={!!status && !!status.success}
        error={!!errors.submit}
        onSubmit={handleSubmit}>

        <FormInput
          value={values.oldPassword || ''}
          onChange={handleChange}
          type='password'
          placeholder='Old Password'
          name='oldPassword'
        />

        <FormInput
          value={values.passwordOne || ''}
          onChange={handleChange}
          type='password'
          placeholder='New Password'
          name='passwordOne'
        />

        <FormInput
          value={values.passwordTwo || ''}
          onChange={handleChange}
          type='password'
          placeholder='Confirm New Password'
          name='passwordTwo'
        />

        <Button disabled={!isValid} type='submit'>
          Reset My Password
        </Button>

      </Form>
    }
  </Formik>

Hi there ... this last suggestion hasn't helped me. Any other ideas as to how to refresh the form after submission. I'm using the render prop method for Formik. I need the input field to clear but the resetForm() method is not having any effect.

// Render Prop
import React from 'react';
import { Formik } from 'formik';

import { addItem} from '../actions/pred-actions.js';
import Button from '@material-ui/core/Button';
import MatInput from '@material-ui/core/Input';
import '../css/addForm.css';

const FormikBasic = ( props ) => {

  let { user } = props;
  console.log("FormikBasic user:", user);

  return (
  <div>
    <h1>New Item</h1>
    <p>Proposed by {user.firstname}</p>

    <Formik
      initialValues={{
        short: ''
      }}
      validate={values => {
        let errors = {};
        if (!values.short) {
          errors.short = 'Required'
        }
        return errors;
      }}
      onSubmit={(
        values,
        { setSubmitting, setErrors, resetForm /* setValues and other goodies */ }
      ) => {
        console.log("Form submitted...");
        addItem(user, values.short).then(result => {
          console.log("addItem result:", result);
          setSubmitting(false);
          console.log("Add Values:", values);
          resetForm({}); // <= This isn't having the effect of clearing the form so the input field is not clearing
          // handleReset();
        }, errors => {});

      render={({
        values,
        errors,
        touched,
        handleChange,
        handleBlur,
        handleSubmit,
        // resetForm,
        handleReset,
        isSubmitting,
      }) => (

        <form onSubmit={handleSubmit}>

          <div>
          <MatInput

            type="textarea"
            name="short"
            onChange={handleChange}
            onBlur={handleBlur}
            placeholder="Short name..."

          />
          {touched.short && errors.short && <div>{errors.short}</div>}

          <Button variant="contained" color="primary" type="submit" disabled={isSubmitting}>
            Submit
          </Button>
          </div>

        </form>

      )}
    />
  </div>
)};

export default FormikBasic;

@notgoodwithpowertools have you tried passing value = values.short || '' to your input component

You sir are a legend. Props to you !! and so fast on the reply too!! Thank you ... been working this all night. This has it working now with the text entry clearing after submit. How do I buy you a beer :-)

<MatInput
            value={values.short || ''} // <= Suggested change
            type="textarea"
            name="short"
            onChange={handleChange}
            onBlur={handleBlur}
            placeholder="Short name..."

          />

Your thanks is more than enough 馃榿

What a headache I got from this. So, yeah, @joserocha3 solution works. In my case, though, I passed the initial values to the resetForm:

const initialValues = { address: '' };
...
<Formik initialValues={initialValues}>
  {({ resetForm }) => (
    <Form>
      <Field name="address" label="Address"/>
      <Button
        type="button"
        onClick={() => resetForm(initialValues)}
      >
        cancel
      </Button>
    </Form>
  )}
</Formik>

Thanks!

Is there a way to accomplish this when I am using sagas?

Should I send handleReset to a saga and fire it there on successful response?

@flppv Had the same problem here (and with the setSubmitting function), but I didn't wanted to send callbacks to sagas.
My solution : refresh the form state.

How does it look :

export function LoginForm({error, submittedValues}) {
  return (
   <Formik
      key={error ? 'error' : 'form'}
      initialValues={submittedValues || initialValues}
      render={...}
    />
  );
}
// ... connect to redux store ...

submittedValues is populated w/ the form submitted values at the "submitting" stage ;
error is populated w/ the saga error at the "submitted" stage ;
Using key in this way rebuild the whole form (w/ the user inputed values in my case) only once the "submission" flow is ended.

I noticed resetForm() only works if we pass a new value like resetForm({field: "", field2: ""})
so I didn't want to add all my fields manually so what we did is to reset all fields commit from values and then pass thought resetForm(values)
javascript const onHandleSubmit = () => ( values, { setSubmitting, setStatus, resetForm, error } ) => { addNewClient({ variables: values}) .then(result => { Object.keys(values).forEach(key => (values[key] = "")); //<-----------RESETTING ALL FIELDS using blank space resetForm(values); //<--------------PASING TO resetForm the all empty fields showSuccess(`${result.data.addClient.name} created`); setStatus(true); }) .catch(err => { showGraphQLError(err); setStatus({ success: false }); setSubmitting(false); setErrors({ submit: error.message }); }); }

formik.resetForm({}) doesn't clear the form but formik.resetForm() does.

#resetform-nextinitialstate-formikstatevalues--void

if you are using sagas use a ref to formik and than call

componentDidUpdate(prevProps, prevState) {
 // reset form 
// some condition ...
this.formik.resetForm();
}
<Formik
 ref={(ref) => this.formik = ref}
...

from your component did update method

Hi, not sure if this helps but here is how I handled it using:

  • React 16.8
  • Formik
  • Material UI
export const LogInForm: React.FC<RouterProps> = (props): ReactElement => {
    const [userSubmittedFormValues, setUserSubmittedFormValues] = useState({ email: '', password: '' });

  return (
    <Formik
       onReset={(values): void => setUserSubmittedFormValues(values)}
       onSubmit={ /* my onSubmit logic here */ }
       /* Remainder of my form logic here... */

      render={({ values, handleBlur, handleChange, handleRest }): ReactElement => (
      <Button onSubmit={handleReset}>Log in</Button>
    />
  • I created local state for my login form
  • When I submit the form via my Material UI button, I call handleSubmit
  • In my onReset prop with <Formik />, I set the user submitted values to state in case I need them. Which for my case, I'm using the user submitted values for some error handling I want to do.

This way, I'm able to:

  • Reset the form on submit immediately
  • Keep in state what the user submitted to my form
  • I'm not using a custom wrapper around Formik
  • I'm not using an additional package outside of Formik (e.g., formik-material-ui)

Hope this helps.

@rwschmitz

Reset the form on submit immediately

I'd say this is a bad idea. What if the form doesn't submit, or the server responds with an error. you'll make the user refill the form again in order to try to submit one more time.

Can we reset form from outside funtion?

When I reset, the formik.values clears but the form itself keeps the input data. Any ideas?

https://codesandbox.io/s/formik-example-nfl55?fontsize=14&hidenavigation=1&theme=dark

For anyone, here is the solution:

```
initialValues={initialValues}
validationSchema={validationSchema}
validateOnBlur={false}
validateOnChange={false}
onSubmit={async (values, { resetForm }) => {
await onSubmit(values)

  resetForm()
}}

>

@defusioner worked perfectly for me! thanks man

You can reset the form on submission by passing in a second argument in form of an object for your handleSubmit function.

    const handleSubmit = async (values, { resetForm }) => {
        try {
            let res = await axios.post('http://localhost:5003/api/v1/change', values, { headers: { Accept: 'application/json' } });
            // console.log(res)
            resetForm();
        }
        catch (err) {
            console.log(err);
            setErr(err.message);
        }
    }

<Formik 
onSubmit={handleSubmit}
> 
...Your form here
</Formik>

Is there a way to accomplish this when I am using sagas?

Should I send handleReset to a saga and fire it there on successful response?

For @flppv anyone else struggling with clearing on submit (but not on error) using sagas, here's how I managed to get it working:

<Formik initialValues={{ ...data }} onSubmit enableReinitialize={!hasError} >

The {...data} comes from the store and is only updated when the submit is successful. onSubmit is a simple dispatch of the values with a saga hooked up to an api.

If submit is not successful, an error is set in the store that ends up as hasError in the above. So the form is only re-initialized with the updated data if there is no error, but if there is an Error then the form can be re-submitted or whatever.

Hi,
I want to reset a specific Field to one particular value. I have a dropdown field, and when I reset, I want to give it a specific value: "Choose Category" in this case.

Does anyone have an idea how to solve this?

<Field name='categoryId' component={CategoryDropDown} />

here is the component:

```import React, { useState, useEffect } from 'react';
import {
UncontrolledDropdown,
DropdownToggle,
DropdownMenu,
DropdownItem
} from 'reactstrap';
import { getCategories } from '../../../client';

const CategoryDropDown = props => {
const [selectedCategoryName, setSelectedCategoryName] = useState('Choose Category');
const [categories, setCategories] = useState([]);

useEffect(() => {
getCategories().then(res => {
setCategories(res.data);
});
}, []);

const handelChange = e => {
setSelectedCategoryName(e.target.name);
props.form.setFieldValue(props.field.name, e.target.value);
};

return (


{selectedCategoryName}


{categories.map(category => (
key={category.id}
onClick={handelChange}
value={category.id}
name={category.name}
>
{category.name}

))}


);
};

export default CategoryDropDown;
```

Thank you all guys!

What if we use multiple steps of 3 forms, so after a successful process, we have to return to the first form but this time to begin a new subscription,

resetForm({}) is working but what if we have to alter some fields

import React, { Component } from 'react';
import { Formik } from 'formik';
import * as Yup from 'yup';

const schema = Yup.object({
    name: Yup.string().min(3).max(30).required().label('name'),
    email: Yup.string().email().required().label('email'),
    message: Yup.string().min(10).max(512).required().label('message')
});

class ContactForm extends Component {

    onSubmit = async (values, actions) => {
        try {
            actions.setSubmitting(true);
            const resp = await // your API Call .... ;
            if (resp.success) {
                actions.resetForm();
            } else {
                 // your failure scenario...
            }
        } catch (err) {
            // your error scenario....
        }
    }

    render() {
    <Formik initialValues={{name: ''}} validationSchema={schema} onSubmit={this.onSubmit}>
        {({ handleSubmit, handleChange, handleBlur, values, errors, touched}) => (
           <form onSubmit={handleSubmit}>
               <input
                   value={values.name || ''}
                   name="name"
                   type="text"
                   values={values.name}
                  onChange={handleChange}
                  onBlur={handleBlur} 
               />
               {errors.name && touched.name ? {errors.name} :  null }
               <button type="submit"> Submit 
                        {isSubmitting ? <Spinner color="#fff" size={24} /> : null} 
              </button>
        </form>
       )}
    </Formik>
  }
}

Thank you,
I solved by splitting the forms into three steps ...

instead of passing anything into the resetForm({}) function use just resetForm(). this worked for me
initialValues={{
short: ''
}}
validate={values => {
let errors = {};
if (!values.short) {
errors.short = 'Required'
}
return errors;
}}
onSubmit={(
{ short },
{ setSubmitting, setErrors, resetForm /* setValues and other goodies */ }
) => {
console.log("Form submitted...");
addItem(user, short).then(result => {
console.log("addItem result:", result);
setSubmitting(false);
console.log("Add Values:", values);
resetForm(); // <= Change this
}, errors => {});

i was trying to set form with updated values and after going though comments and test i found following

  1. resetForm() : sets values to initial values of the form. If mapPropsToValues was used then it will reset to those values
  2. To update the form with updated values use setValues(updatedValuesObject)

Any ideas how to get this working using react native? - Trying the suggestions above but it's still not functioning correctly. :(

Warning: An unhandled error was caught from submitForm() [TypeError: undefined is not an object (evaluating '_ref2.resetForm')]

What a headache I got from this. So, yeah, @joserocha3 solution works. In my case, though, I passed the initial values to the resetForm:

const initialValues = { address: '' };
...
<Formik initialValues={initialValues}>
  {({ resetForm }) => (
    <Form>
      <Field name="address" label="Address"/>
      <Button
        type="button"
        onClick={() => resetForm(initialValues)}
      >
        cancel
      </Button>
    </Form>
  )}
</Formik>

Thanks!

It's not clearing file input field.

I have Formik form with three field title, description and image. Field "image" type is file. After submitting when I reset form using resetForm(), it's clearing the title and description but image is not clearing. I have also tried resetForm({ title: "", description: "", image: null // and image: "" }) but none of worked.

Have anyone idea how to clear file input also ?

@kishanbharda I had the same issue and I managed it creating a ref in the parent component (the one that use Formik) and passing it to the field using innerRef prop.
Then on the onReset I used the ref to clear the real input value.

const UserForm = props => {
    const logoRef = useRef();

    const handleReset = (values, formikBag) => {
        logoRef.current.value = null; //THIS RESETS THE FILE FIELD
    }

    const handleSubmit = (values, formikBag) => {
        //...
        axios({method, url, data})
            .then(response => {
                formikBag.resetForm();
            })
    //...
    return (
        <Formik initialValues={initialValues} onSubmit={handleSubmit} onReset={handleReset}>
            ...
            <Field
                type="file"
                name="logo"
                onChange={({target}) => setFieldValue(props.name, target.files[0])}
                innerRef={logoRef}
            />
        </Formik>
    )
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

najisawas picture najisawas  路  3Comments

jaredpalmer picture jaredpalmer  路  3Comments

najisawas picture najisawas  路  3Comments

sibelius picture sibelius  路  3Comments

jaredpalmer picture jaredpalmer  路  3Comments