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;