Home > OS >  Multiple forms in react
Multiple forms in react

Time:05-26

I have multiple forms like below

<form>
  <TextField ..../>
  <TextField ..../>  
   Calling another child component here
</form>

Child Component also has a form like below

<form onSubmit={handleSubmit(onTrigger)}>
  <TextField ..../>
  <select ..../> 
   <Button variant="contained" type="submit">Submit</Button> 
</form>

How can I handle these two forms in one submit operation. Is it possible? I'm new to react, please share your insights.

CodePudding user response:

You could make both forms controlled components, i.e. store the input values in state variables whenever they change. Then, you use the same onSubmit function for both forms.

Maybe it'd be easier if you used only one form if that's possible.

CodePudding user response:

I really recomment Formik, you can read more about it here: https://formik.org/docs/overview

Here is an example of exactly what you want (look how short it is):

CodeSandbox: https://codesandbox.io/s/wu7yj

You should have three files:

App.jsx

import React from "react";
import FormA from "./FormA";
import FormB from "./FormB";

export default function App() {
  const [formData, setFormData] = React.useState({
    formA: { values: null, validated: false },
    formB: { values: null, validated: false },
  });

  const formAref = React.useRef();
  const formBref = React.useRef();

  React.useEffect(() => {
    if (formData.formB.validated && formData.formA.validated) {
      alert("Ready to save");
    }
  }, [formData]);

  async function handleSubmit() {
    await formAref.current.Submit();
    await formBref.current.Submit();
  }

  function handleChangeFormA(data) {
    setFormData({ ...formData, formA: data });
  }

  function handleChangeFormB(data) {
    setFormData({ ...formData, formB: data });
  }

  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>

      <FormA onChange={handleChangeFormA} refId={formAref} />
      <FormB onChange={handleChangeFormB} refId={formBref} />

      <button
        onClick={() => {
          console.log(formData);
        }}
        type="button"
      >
        set
      </button>

      <button onClick={handleSubmit} type="button">
        Submit
      </button>
    </div>
  );
}

FormA.jsx

import React from "react";
import { useFormik } from "formik";
import * as Yup from "yup";

const FormA = ({ onChange, refId }) => {
  const formik = useFormik({
    initialValues: {
      name: "",
      email: ""
    },
    validationSchema: Yup.object({
      name: Yup.string().required("This field is required"),
      email: Yup.string()
        .email("Invalid email address")
        .required("Email is required")
    }),
    onSubmit: () => {
      watchForm();
    }
  });

  // React.useEffect(() => {
  //   watchForm();
  // }, [formik.values, formik.errors]);

  React.useImperativeHandle(refId, () => ({
    Submit: async () => {
      await formik.submitForm();
    }
  }));

  function watchForm() {
    if (onChange) {
      onChange({
        values: formik.values,
        validated: formik.isSubmitting
          ? Object.keys(formik.errors).length === 0
          : false
      });
    }
  }

  return (
    <form ref={refId}>
      <div className={"form"}>
        <h3>Form A</h3>
        <div>
          <label>Name </label>
          <input
            name="name"
            value={formik.values.name}
            onBlur={formik.handleBlur}
            onChange={formik.handleChange}
          />
          {formik.errors.name && (
            <div style={{ color: "red" }}>
              <small>{formik.errors.name}</small>
            </div>
          )}
        </div>
        <br />
        <div>
          <label>Email </label>
          <input
            name="email"
            value={formik.values.email}
            onBlur={formik.handleBlur}
            onChange={formik.handleChange}
          />
          {formik.errors.email && (
            <div style={{ color: "red" }}>
              <small>{formik.errors.email}</small>
            </div>
          )}
        </div>
        <pre>{JSON.stringify(formik.values, null, 2)}</pre>
      </div>
    </form>
  );
};

export default FormA;

Formb.jsx

import React from "react";
import { useFormik } from "formik";
import * as Yup from "yup";

const FormB = ({ onChange, refId }) => {
  const formik = useFormik({
    initialValues: {
      phone: ""
    },
    validationSchema: Yup.object({
      phone: Yup.string()
        .required("This field is required")
        .min(6, "At least 06 characters")
    }),
    onSubmit: () => {
      watchForm();
    }
  });

  // React.useEffect(() => {
  //   watchForm();
  // }, [formik.values, formik.errors]);

  React.useImperativeHandle(refId, () => ({
    Submit: async () => {
      await formik.submitForm();
    }
  }));

  function watchForm() {
    if (onChange) {
      onChange({
        values: formik.values,
        validated: formik.isSubmitting
          ? Object.keys(formik.errors).length === 0
          : false
      });
    }
  }

  return (
    <form ref={refId}>
      <div className={"form"}>
        <h3>Form B</h3>
        <div>
          <label>Phone number </label>
          <input
            name="phone"
            value={formik.values.phone}
            onBlur={formik.handleBlur}
            onChange={formik.handleChange}
          />
          {formik.errors.phone && (
            <div style={{ color: "red" }}>
              <small>{formik.errors.phone}</small>
            </div>
          )}
        </div>

        <pre>{JSON.stringify(formik.values, null, 2)}</pre>
      </div>
    </form>
  );
};

export default FormB;
  • Related