How do you update Formik initial values with the react context api values after an AJAX request?
Asked Answered
P

3

35

The issue I’m facing though is that I want to mimic the behaviour of the FlaskLogin current_user in React throughout the component treed. For anyone that’s not familiar with FlaskLogin, current_user just stores a session of the user who’s currently logged in.

To do this, I decided on using the React context api. What I do is at the top level component, I wrap a UserProvider around the app as so:

<UserProvider value={this.state.user}>
    // Main Component.
</UserProvider>

The state is defined in the constructor:

constructor() {
    super();
    this.state = {
      user: {
        id: -1,
        username: ‘test username’,
        email: 'test email’,
      },
    };
  }

And then I call an Ajax request in the componentDidMount to grab the current_user.

componentDidMount() {
    const state = this;
    post('/get_current_user').then(function success(data) {
      state.setState({
        user: {
          id: data.data.id,
          username: data.data.username,
          email: data.data.email,
        },
      });
    }).catch(function exception() {
      throw new Error('Failed to grab current user.');
    });
  }

I can grab this updated context throughout the app. This works great for an “ProfilePicture” component as it grabs the correct state but it doesn’t work for setting the initial values with Formik. In Formik I am creating an update username and email form. The issue is that Formik gets the context api values BEFORE the context api has been updated through the AJAX request. So “test username” will show up in the username field and “test email” will show in the email field. My Formik form is as follows:

const UserSettingsProfileForm = () => {
  return (
    <UserConsumer>
      {context => (
        <Formik
          initialValues={{ email: context.email, username: context.username }}
          validationSchema={userSettingsFormSchema}
          onSubmit={userSettingsOnSubmit}
          render={userSettingsForm}
        >
        </Formik>
      )}
    </UserConsumer>
  );
};

Does anyone have any suggestions on how to fix this so the correct context api values show up?

Porterhouse answered 27/3, 2019 at 21:48 Comment(2)
To anyone who finds this answer in the future, the solution is to set the enablereinitialize prop to true. jaredpalmer.com/formik/docs/api/…Porterhouse
That should be enableReinitialize (mind the capital 'R')Everyday
L
80

You should set the enableReinitialize prop.

<Formik
  initialValues={{ email: context.email, username: context.username }}
  enableReinitialize
Linguiform answered 22/1, 2021 at 18:12 Comment(1)
is it considered a bad practice to update initial values? since it is disabled by defaultPrecognition
L
7

According to official github issue from Formik you should add enableReinitialize prop: https://github.com/formium/formik/issues/811#issuecomment-410813925

Lashaun answered 10/3, 2021 at 11:32 Comment(1)
How can I preserve my edited values of the form when the initial values get updated?Credo
A
5

If you are using useFormik (formik hooks),

add the enableReinitialze prop on to the configuration object.

 import React from 'react';
 import { useFormik } from 'formik';
 
 const SignupForm = ({ newInitValues }) => {
   const formik = useFormik({
     initialValues: newInitValues || {
       firstName: '',
       lastName: '',
       email: '',
     },
     onSubmit: values => {
       alert(JSON.stringify(values, null, 2));
     },
     enableReinitialze: true,
   });
   return (
     <form onSubmit={formik.handleSubmit}>
       <label htmlFor="firstName">First Name</label>
       <input
         id="firstName"
         name="firstName"
         type="text"
         onChange={formik.handleChange}
         value={formik.values.firstName}
       />
       <label htmlFor="lastName">Last Name</label>
       <input
         id="lastName"
         name="lastName"
         type="text"
         onChange={formik.handleChange}
         value={formik.values.lastName}
       />
       <label htmlFor="email">Email Address</label>
       <input
         id="email"
         name="email"
         type="email"
         onChange={formik.handleChange}
         value={formik.values.email}
       />
       <button type="submit">Submit</button>
     </form>
   );
 };
Apocalyptic answered 9/5, 2022 at 18:21 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.