Search code examples
javascriptreactjsformikformik-material-ui

Data from API is not filled inputs fields. Formik


I create simple form on functional component ReactJS, with using Formik. Input fields my form should get data from API, when component mount. For this i'm using fetch and useEffect. After fetching, data from the API is retrieved but not filled until formik.handleChange is triggered.

If try to specify something in any input field, formik.handleChange is triggered, and all fields are immediately filled with data from the API (in my case, sould filled only email)

How i can triggered formik.handleChange when component will mount ?

import React, { useEffect } from 'react';
import { TextField, Button } from '@material-ui/core/';
import { useFormik } from 'formik';
import * as yup from "yup";

const validationSchema = yup.object({

  Title: yup.string("Enter your Title").required("Title is required"),
  email: yup
    .string("Enter your email")
    .email("Enter a valid email")
    .required("Email is required"),
});

export default function Form() {

const formik = useFormik({
    initialValues: {
      Title: "",
      email: ""
    },
    validationSchema: validationSchema,
    onSubmit: async (values) => {
      //...code of post function
      //...code of post function
      //...code of post function
    }
  });

    useEffect(() => {
    (async () => {
      try {
        let response = await fetch(
          "https://run.mocky.io/v3/5be581aa-89d3-43e3-8478-7186633f8d16"
        );
        let content = await response.json();
        formik.initialValues.email = content[0].email;
      } catch (e) {
        console.log(e);
      }
    })();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

    return (
        <form onSubmit={formik.handleSubmit}>
            <TextField
                fullWidth
                id="email"
                name="email"
                label="Email"
                value={formik.values.email}
                onChange={formik.handleChange}
                error={formik.touched.email && Boolean(formik.errors.email)}
                helperText={formik.touched.email && formik.errors.email}
            />
            <Button color="primary" variant="contained" fullWidth type="submit">
                Submit
            </Button>
        </form >

    );
}

Link to SandBox

In addition, I have a second way with using ReactState, but I think it way are lesspreffered but it has another error: After fetching, states fill my input fields, but fail validation. When i'm trying submiting data, to validation sending default values of react State (those that came before fetch)

Link to SandBox with useState way


Solution

  • You were on a good path. Reassigning values to formik instance will not help. Use setFieldValue to set value after fetching data (or simply setValues if you want to set all values):

    formik.setFieldValue("email", content[0].email);
    

    or:

    formik.setValues(content[0]);
    

    Here's a modified version of your Sandbox: https://codesandbox.io/s/jolly-sun-uppr6?file=/src/App.js

    Don't forget to set your formik to enable reinitialize - https://formik.org/docs/api/formik#enablereinitialize-boolean