formik: Formik does not re-render when initialValues change

Current Behavior

If there is an “external” component controlling initialValues passed to Formik, Formik never updates it. This may be desired behavior, however in my specific case I need to re-render the form (and ideally, warn the user about unsaved changes) with new initialValues. If this is not a bug, any ideas on how to achieve this?

Steps to Reproduce

  1. Open https://codesandbox.io/s/kworjlq7n3
  2. Toggle between the select options
  3. You will see that all components in the chain re-render with new values, however Formik render never changes initialValues.

Expected behavior

When initialValues change, Formik should trigger a re-render and provide new initialValues in its render method.

CodeSandbox Link: https://codesandbox.io/s/kworjlq7n3

EDIT: CodeSandbox demonstrates a working solution


  • Formik Version: 1.0.2
  • React Version: 16.3.2
  • TypeScript Version: N/A
  • Browser and Version: Chrome Version 68.0.3440.84 (Official Build) (64-bit)
  • OS: Mac OS 10.13.4

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 89
  • Comments: 122 (4 by maintainers)

Most upvoted comments

Aaaaaaaand… solved couple minutes after submitting this. The missing piece was enableReinitialize prop.

Since this is open now, I’ll use the opportunity to ask if there is a way to

  1. listen on reinitialization
  2. cancel it

Thanks

 <Formik
        enableReinitialize // missing piece!!
        initialValues={props.initialValues}

working here

May I suggest to the authors of Formik that the default value of this defaults to true? It is counter-intuitive for it to behave this way without explicitly stating it

I just lost hours of coding because of this.

Doesn’t work for me …

does not work for me…

For me the presence of the enableReinitialize property doesn’t change anything. If the form hasn’t been touched (dirty = false) the form is re-rendered if any property in initialValues is changed from outside of Formik. So far as expected. Once the form is changed by any user input (dirty = true), changes to the initialValues triggers the render function but does not re-write the values within the form. Thanks for any suggestions!

enableReinitialize doesn’t work for me either.

Or you can set the element key like so: <Formik key={someId} ...

This tells react that this element has changed and should be re-rendered.

https://en.reactjs.org/docs/lists-and-keys.html#keys

Keys help React identify which items have changed, are added, or are removed. Keys should be given […] to give the elements a stable identity

enableReinitialize still doesn’t work for me. The state changes but, inner values does not changes.

My code:

   <Formik
                    initialValues={this.state.initialFormData} // this changes over time but still values don't get changed
                    validationSchema={validationSchema}
                    onSubmit={this.handleSellerPwd}
                    render={this.renderSellerPwdForm}
                    enableReinitialize={true}
                />

There are few different issues people are talking about in this issue so it’s kind of hard to parse through the different threads. I’m going to try to help parse out the conversation as I understand it. I may get some things wrong.

  1. Some people are changing the initialValues prop value and not seeing the form reset. This is by design and you have to set enableReinitialize to make Formik re-initialize when a new initialValues prop value is set. https://github.com/jaredpalmer/formik/issues/811#issuecomment-410813925
  2. Some people are passing a new object for the initializeValues prop that is deeply equal to the previous initializeValues prop. They have also set enableReinitialize to true, but still aren’t seeing Formik re-initialize. This is because Formik apparently doesn’t re-initialize if the new initialValues is deeply equal to the old initialValues, even if they are different objects in memory. It sounds like the appropriate fix is to call resetForm instead of trying to set initialValues or do some hack to make the objects not deeply equal. https://github.com/jaredpalmer/formik/issues/811#issuecomment-936601980
  3. Some people are setting a new initialValues object and have set enableReinitialize to true, but are noticing that on the next render of Formik descendants that Formik is providing the prior initialValues and not the new initialValues. If another render occurs later and Formik provides the new initialValues, it can result in a React warning like Warning: A component is changing an uncontrolled input of type text to be controlled.. This (to me) appears to be a bug in Formik and is solved by setting a key value on Formik that changes every time you set a new initialValues. https://github.com/jaredpalmer/formik/issues/811#issuecomment-505495937

I am now giving the Formik component a key of JSON.stringify(row) to force formik to update when my filter and thus my row object changes. But that is a bit of a hack.

Worked for me also, and I agree with @danieltodonnell , this is counter intuitive and I also spent hours searching the docs and the web to reach this thread as others have mentioned.

@linuxgg For god sake, you save my day

@robwold initially this is exactly how Formik worked. However, a lot of folks passing in data from redux wanted a way to turn this off. So we came up with enableReinitialize.

you guys just need to follow the steps bellow:

  1. Set the enableReinitialize on Formik component;
  2. Set an initial state for the initialValues variable (useState for who is working with hooks);
  3. Update the initialValues to the new one inside your side effect (useEffect for who is working with hooks or componentDidMount / componentDidUpdate).

Going to tackle better in docs.

It works for me by setting initialValues to empty string with useState

const [initialValues, setInitialValues] = useState({
    name: "",
    age: "",
    email: "",
  });

Then set enableReinitialize to true for Formik. enableReinitialize={true} Then use UseEffect to update the form when the screen loads.

I encountered one error where enableReinitialize doesn’t do anything. The problem is that I wrapped around Formik to create customized Form component and I forgot to pass enableReinitialize to my customized form component… That took me an hour to figure out… Hope my experience could help if enableReinitialize doesn’t work for you.

@jaredpalmer took me hours to track this one down too. I’m new to both React and Formik, so there might well be a really good reason why this is the default behaviour. But part of the promise of Formik is that it’s “just React, and your Formik problems are really React problems”, and it seems to me that having your form not update with your state/props is a case where Formik really goes against the grain of React (and, arguably, the whole point of using React).

e.g. My use case was that when my page loads, I get the user’s existing data for them to edit from an API call in componentDidMount, which overwrote empty values set in the constructor. This is how tutorials tell you to do this sort of thing, so I’m sure that this pattern is pretty common? For details on how confused I got by this, see https://stackoverflow.com/questions/56246765/formik-values-not-updating-with-state/56252261#56252261

@jaredpalmer it would be great if the documentation provided a rationale for the choice to set enableReinitialize to false. I’m having trouble pinpointing the use case for it being false. Is it because formik can’t tell how the properties are mapped to initial values? So an unrelated property could change, but the form’s values shouldn’t be reset because of it? But if that’s the case, isn’t this a design flaw in the protocol used between the parent component and the component that’s withFormik-wrapped? In other words, it’s something you’d want for the developer to fail during testing (if they change a property to a form that’s unrelated to its values?). I still feel I don’t quite get formik.

For those who complain that the enableReinitialize is not working, make sure you are updating the initialValues using react local state. Consider these code:

const [initialValues, setInitialValues] = useState(INITIAL_FORM_STATE);

//... update state on API Call
useEffect(() => {
    api.getUserById(id)
      .then( data => setInitialValues(data));
}, [id]);

//... on formik
<Formik
  enableReinitialize={true}
   initialValues={initialValues} // this changes over time but still values don't get changed
   {/* rest goes here */}
>
{/* rest goes here */}
</Formik>

@jaredpalmer: Frist of all, Formik is absolutely great! Thanks so much! It does not really matter if the enableReinitialize setting is true/false but what is absolutely important that, 1.) enableReinitialize is mentioned in every example with a short note, including the Getting Started Guide. 2.) enableReinitialize has a better documentation. The Description is not obvious for a newbie. For a newbei sth. like “Tracking State” is much more obvious term. Resetting was the last I thought when I was looking for a solution. So many people report here having searched hours to solve the problem (including me). Please make this more ovious. Thanks so much.

This thread saved me, thank you. Also agree that enableReinitialize should be enabled by default.

@iamvanja Thanks so much for posting this issue and its solution. Seriously was driving myself nuts.

There are few different issues people are talking about in this issue so it’s kind of hard to parse through the different threads. I’m going to try to help parse out the conversation as I understand it. I may get some things wrong.

  1. Some people are changing the initialValues prop value and not seeing the form reset. This is by design and you have to set enableReinitialize to make Formik re-initialize when a new initialValues prop value is set. Formik does not re-render when initialValues change #811 (comment)
  2. Some people are passing a new object for the initializeValues prop that is deeply equal to the previous initializeValues prop. They have also set enableReinitialize to true, but still aren’t seeing Formik re-initialize. This is because Formik apparently doesn’t re-initialize if the new initialValues is deeply equal to the old initialValues, even if they are different objects in memory. It sounds like the appropriate fix is to call resetForm instead of trying to set initialValues or do some hack to make the objects not deeply equal. Formik does not re-render when initialValues change #811 (comment)
  3. Some people are setting a new initialValues object and have set enableReinitialize to true, but are noticing that on the next render of Formik descendants that Formik is providing the prior initialValues and not the new initialValues. If another render occurs later and Formik provides the new initialValues, it can result in a React warning like Warning: A component is changing an uncontrolled input of type text to be controlled.. This (to me) appears to be a bug in Formik and is solved by setting a key value on Formik that changes every time you set a new initialValues. Formik does not re-render when initialValues change #811 (comment)

This last one saved my life. thanks.

I had problem with dirty form as @adammolnar mentioned so instead of reinitializing formik I have used form.resetForm(newValuesObject);

Docs: https://jaredpalmer.com/formik/docs/api/formik#resetform-nextvalues-values-void

When I use enableReinitialize along with reac-text-mask, the value is not changed. Has anyone had this problem before

Reinitializing is a destructive (and expensive) operation and will override any changes your users have made to your form. Just checking for reinitialization isn’t a free operation, depending on the size of your form states. Many people pass initial values like:

<Formik initialValues={{ firstName: '', lastName: ''}} />

On every render, Formik would have to do a deep equals of those initialValues to make sure they are referentially equal. Since this is such a common pattern, Formik skips these checks by default and provides a simple opt-in to these checks, enableReinitialize.

After opting in, you can get your initialValues from anywhere, but that anywhere has to trigger a render in React, which eventually comes down to Props or a Hook, whether a library-provided hook like Relay or Redux, or the result of a setState or dispatch when manually calling an API.

After reinitialise validations are not working…!!!

@godmar I figured it out … You have to set value={field.value || ''} in the input inside the TextInput component or whatever type you’re using in order to fix this issue.

Making enableReinitialize true by default would have been nice. Or, make it as a required prop if that is such a thing in react, so we are forced to put something in there, and will make appropriate decision accordingly. However, loving Formik, and appreciate your hard work.

@jaredpalmer That was a fast response, thanks! I’m on 1.5.1. I appreciate that for Open Source you’ve got to balance the competing interests of different users, all of whom owe you something and not the other way round - just wanted to provide some feedback, especially as I’m not the only one who’s been caught out by this.

If anyone is still facing this issue even after setting enableReinitialize to true, Give formik a key that changes on every render like Date.now(), This is what worked for me.

Thanks @Aaronius for a good explanation on different scenarios.

@giriss, yes, it is very common (though less frequent with hooks) for a developer to write the object inline:

const [myValue, setMyValue] = useState('no'),

useEffect(() => setMyValue('yes'), []);

<Formik initialValues={{
    myValue,
  }} />
</Formik>

If we did not do a deep comparison, Formik would reinitialize on every render in this scenario. This is more frowned upon with hooks since devs are generally expected to use state, but it’s still a fallback that I wouldn’t recommend removing.

If you are trying to reset the form with the same values, you can use formik.resetForm().

While editing the form, every time I change the value, the whole form re-renders and validation goes away for the fields which already appeared. Can anyone guide me please?

@rom5jp @saymow @DevMammadov codesandbox repro will help someone investigate your specific issue

@rom5jp @saymow I’d guess you need to translate the handleChange or handleBlur from your third party input library of choice to Formik’s api

@devmammadov I’d guess you need to memoize your API call / initialValues so that repeated API calls don’t cause the reinitialization

const MyForm = () => {
  const [apiResult, updateApiResult] = useState();
  const [initialValues, updateInitialValues] = useState(getDefaultInitialValuesWithoutApiResult());

  const apiUpdater = useCallback(async () => {
    const result = await fetch('/api/endpoint');
    
    result && updateStateFromApiResult(result);
  }

  useEffect(
    () => updateInitialValues(getInitialValuesWithApiResult(stateFromApiResult)),
    [Boolean(apiResult)] // only update once when receiving first result 
  );

  return <Formik initialValues={initialValues} />;
}

But there’s not much I can help with without a repro.

@godmar I figured it out … You have to set value={field.value || ''} in the input inside the TextInput component or whatever type you’re using in order to fix this issue.

That has the same effect as making sure that all values are set in initialValues. The error occurs if a value is undefined, which you avoid with your || '' fallback.

I am now giving the Formik component a key of JSON.stringify(row) to force formik to update when my filter and thus my row object changes. But that is a bit of a hack.

after few hours of searching for answers and trying to fix this problem with re-render your “hack” is the only thing that worked! thanks!

Aaronius

Thanks for clarifying in such a nice way!

enableReinitialize is reseting all values to initial everytime i do a state change

when the enableReinitialize is set, and then the observer value changes, it resets the entire form and it only updates the field of the observer.

Is there a way to a preserve the form and I just update the observer field? TIA!

I think I know the answer to why the form does not reinitialize!! I guess Formik is comparing objects deeply!

For example

const INITIAL_VALUES = Object.freeze({
  x: "x",
  y: "y",
});

function SomeComponent() {
  const [isModalOpen, setIsModalOpen] = useState(false);
  const [initialValues, setInitialValues] = useState({...INITIAL_VALUES});

  useEffect(() => {
    if (isModalOpen) {
      // we wanna reset the form here right?
      setInitialValues({...INITIAL_VALUES});
    }
  }, [isModalOpen]);

  return (
    <Formik
      enableReinitialize
      initialValues={initialValues}
    >
      {/* Whatever */}
    </Formik>
  );
}

After the useEffect, the 2 initialValues are not equal (===) ! But are deeply equal (if you compare them by attribute). The form does not reinitialize. Since formik does not detect any change in the two initialValues. If you change it, example just adding a fake field, the form will reinitialize.

  useEffect(() => {
    if (isModalOpen) {
      setInitialValues({...INITIAL_VALUES, fakeId: Date.now()});
    }
  }, [isModalOpen]);

Now it works!! It kinda sucks but maybe formik has a reason to deep compare the objects?

please help me, when I define enableReinitialize: true in formik, and defined initialValues then call api asyns to update the values of initialValues, it is not changed the value on the UI, please help me this. thanks so much.

 <Formik
        enableReinitialize // missing piece!!
        initialValues={props.initialValues}

working here

Aaaaaaaand… solved couple minutes after submitting this. The missing piece was enableReinitialize prop.

Since this is open now, I’ll use the opportunity to ask if there is a way to

  1. listen on reinitialization
  2. cancel it

Thanks

This is helping even after years. Thanks.

For enableReinitialize to work for me, I had to use the render method. I couldn’t use the children property, in how you would typically pass children elements to within any other component: i.e. <Formik>{<my form elements />}</Formik> doesn’t work but <Formik render={<my form elements />} /> worked… which is not at all intuitive and wasted me hours…

Believe me, I am quite aware that it is a nuclear approach 😢 ! Unfortunately, although I have used Formik frequently enough in the past, I was unable to get the form reinitializing properly (values did not change). It is possible that my understanding of what gets initialized is flawed (maybe just internal state?), but the only way that I found to properly update the form values/state when parent props change was to “nuke” it by forcing a re-render. Thankfully this is only when the edit state changes, so it is not a large concern (since it re-renders then anyway, and a mount/unmount isn’t too worrisome there).

Even though I also was storing and changing initialValues through useState and had enableReinitialize, the form still wasn’t getting updated when the initial values changed. I eventually had to add a key set to the form’s edit state, to ensure that switching between edit and view modes would force the form to rerender and get potentially new data from Redux.

That is a “nuclear” approach as it unmounts and mounts the form component. Are you sure you are not doing something wrong?

I know this is an old thread, but I think enableReinitialize being false by default is a more sane choice. mostly forms are ephemeral, and you want the values to be set once, worked with, then sent out to a handler and be done.

Or you can set the element key like so: <Formik key={someId} ...

This tells react that this element has changed and should be re-rendered.

https://en.reactjs.org/docs/lists-and-keys.html#keys

Keys help React identify which items have changed, are added, or are removed. Keys should be given […] to give the elements a stable identity

Using key is a better approach. I’m dynamically updating the Form’s initial values and enableReinitialize breaks the form state (e.g. touched fields).

When I use enableReinitialize along with reac-text-mask, the value is not changed. Has anyone had this problem before

I’m facing this same issue when using <InputMask> component from react-input-mask. I’m looking for the solution for this scenario as well.

Adding enableReinitialize saved my bacon! => Thank you!

you guys just need to follow the steps bellow:

  1. Set the enableReinitialize on Formik component;
  2. Set an initial state for the initialValues variable (useState for who is working with hooks);
  3. Update the initialValues to the new one inside your side effect (useEffect for who is working with hooks or componentDidMount / componentDidUpdate).

This worked perfectly for me. Thank you

@johnrom Oh my god. I put attribute like html 😃 Sorry.

@multivoltage you have to pass enableReinitialize={true} to Formik.

I am now giving the Formik component a key of JSON.stringify(row) to force formik to update when my filter and thus my row object changes. But that is a bit of a hack.

Thank-you so much.I had tried : enableReinitialize and bumping up the version, nothing worked except this last resort.Just gave a key with unique value to formik.Probably helps someone in need.Had spent a lot of time worrying I would have to give up on formik because of this.

I’m dynamically generating part of the form, and it always gives me the error … Warning: A component is changing an uncontrolled input of type text to be controlled. Setting enableReinitialize didn’t help. Here’s a StackOverflow post with the issue … https://stackoverflow.com/questions/58205963/formik-update-initial-values-after-api-call

And here’s a link for sandbox … https://codesandbox.io/s/test-dynamic-inputs-with-formik-xr9qg

Any help would be appreciated.

I am now giving the Formik component a key of JSON.stringify(row) to force formik to update when my filter and thus my row object changes. But that is a bit of a hack.

This works with v1.5.1

Aaaaaaaand… solved couple minutes after submitting this. The missing piece was enableReinitialize prop.

Since this is open now, I’ll use the opportunity to ask if there is a way to

  1. listen on reinitialization
  2. cancel it

Thanks

Saved my life

I get the impression that enableReinitialize depends on some lifecycle happening.

Because at first, like many commenting above, I had a hard time getting my form to show any data at all. Then I added enableReinitialize and since then it updates, when initially loading the data from graphql.

But I also have a situation (setting filters), when the form should update due to Mobx state changes.

The form dutifully re-renders every time the filter changes. But formik does not reinitialize its state.

How can I solve this?

@meetzaveri wrong version

Hummmm, OK, I see it is closed. Does that mean there is no way to check if the reinitialization happened?