javascriptreactjsformsvalidationformik

Unable to get the loading state while submitting the form using formik


I have a form component that includes an input field of type number and a button. I am using Formik to manage the form's state. The form component contains a modal that opens when I click the submit button.

The issue I am facing is that there is another button inside the modal, which is type submit. Clicking this button submits the form, but I am unable to access the isSubmitting state from Formik.

import React, { useState, useMemo } from "react";
import { Formik, Form, Field } from "formik";

const FormWithModal = () => {
  const [isModalOpen, setModalOpen] = useState(false);

  const Modal = useMemo(() => {
    if (!isModalOpen) return null;

    return (
      <div className="modal">
        <div className="modal-content">
          <h2>Modal</h2>
          <p>The form has been submitted!</p>
        </div>
      </div>
    );
  }, [isModalOpen]);

  return (
    <div>
      <h1>Form with Modal</h1>
      <Formik
        initialValues={{ numberInput: "" }}
        onSubmit={async (values, { setSubmitting }) => {
          setSubmitting(true);
          // Simulate API call or other async operation
          await new Promise((resolve) => setTimeout(resolve, 1000));
          setModalOpen(true);
          setSubmitting(false);
        }}
      >
        {({ isSubmitting }) => (
          <Form>
            <div>
              <label htmlFor="numberInput">Number:</label>
              <Field
                id="numberInput"
                name="numberInput"
                type="number"
                placeholder="Enter a number"
              />
            </div>
            <button type="submit" disabled={isSubmitting}>
              Submit
            </button>
            {Modal}
          </Form>
        )}
      </Formik>
    </div>
  );
};

export default FormWithModal;



Solution

  • I was able to modify your code and here are some of the adjustments I made.

    1. I added a yup validation to validate the numberinput
    2. I set the submit button in the formik form to a type "button", this way it doesn't trigger the form submission
    3. I passed the handleSubmit function in formik to the submit button inside the modal, so as to trigger the form submission
    4. Inside formik onSubmit function, I updated the formik loading states as well as the modal state in it and I wrapped it inside a setTimeout function.

    I believe this should work for you on a basic level. Feel free to adjust the code to match your use case. see code below

    import React, { useState } from "react";
    import { Formik, Form, Field } from "formik";
    import * as Yup from "yup";
    
    const FormWithModal = () => {
      const [isModalOpen, setModalOpen] = useState(false);
    
      const validationSchema = Yup.object({
        numberInput: Yup.string().required("This field is required"),
      });
    
      return (
        <div>
          <h1>Form with Modal</h1>
          <Formik
            initialValues={{ numberInput: "" }}
            validationSchema={validationSchema}
            onSubmit={(values, { setSubmitting }) => {
              setTimeout(() => {
                console.log("Form submitted with values:", values);
                setSubmitting(false);
                setModalOpen(false);
              }, 2000);
            }}
          >
            {({ errors, touched, isSubmitting, isValid, handleSubmit }) => (
              <>
                <Form>
                  <div>
                    <label htmlFor="numberInput">Number:</label>
                    <Field
                      id="numberInput"
                      name="numberInput"
                      type="text"
                      placeholder="Enter a number"
                    />
    
                    {errors.numberInput && touched.numberInput && (
                      <div className="error">{errors.numberInput}</div>
                    )}
                  </div>
    
                  <button
                    type="button"
                    onClick={() => setModalOpen(true)}
                    disabled={!isValid}
                  >
                    submit
                  </button>
                </Form>
    
                {isModalOpen && (
                  <div className="modal">
                    <div className="modal-content">
                      <h2>Modal</h2>
                      <p>Click "Submit" to submit the form.</p>
    
                      <button type="button" onClick={() => setModalOpen(false)}>
                        Close Modal
                      </button>
    
                      <button
                        type="button"
                        onClick={handleSubmit as any}
                        disabled={isSubmitting}
                      >
                        {isSubmitting ? (
                          <span>
                            <span className="spinner"></span> Submitting...
                          </span>
                        ) : (
                          "Submit"
                        )}
                      </button>
                    </div>
                  </div>
                )}
              </>
            )}
          </Formik>
        </div>
      );
    };
    
    export default FormWithModal;
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js"></script>