I have a form with multiple components in it (with each being either a functional or a class based component) containing multiple input fields or radio buttons. When I submit the form I either want to submit the fields that are nested into components along with the form data or I should be able to extract the fields data and then submit them (not sure which approach would be the best and why?). How can I achieve this?
Code :
import React from "react";
import { useForm } from "react-hook-form";
export default function TestComponent() {
const { register, handleSubmit, errors } = useForm();
const onSubmit = data => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="name">Name</label>
<input type="text" id="name" name="name" ref={register({ required: true, maxLength: 30 })} />
{errors.name && errors.name.type === "required" && <span>This is required</span>}
{errors.name && errors.name.type === "maxLength" && <span>Max length exceeded</span> }
<NestedComponent1 />
<NestedComponent2 />
<input type="submit" />
</form>
);
}
function NestedComponent1() {
return (
<div>
<input type="text" id="nested-name" name="nestedName" />
<input type="text" id="nested-name2" name="nestedName2" />
<input type="text" id="nested-name3" name="nestedName3" />
</div>
);
}
function NestedComponent2() {
return (
<div>
<input type="text" id="nested-comp2-name" name="nestedcomp2Name" />
<input type="text" id="nested-comp2-name2" name="nestedcomp2Name2" />
<input type="text" id="nested-comp2-name3 name="nestedcomp2Name3" />
</div>
);
}
Here are the examples: React Hook Form embraces uncontrolled components and is also compatible with controlled components. Most UI libraries are built to support only controlled components, such as Material-UI and Antd Besides, with React Hook Form the re-rendering of controlled component is also optimized.
Those input components' responsibility is to registering them into react-hook-form. With the Form component injecting react-hook-form 's props into the child component, you can easily create and compose complex forms in your app. Error messages are visual feedback to our users when there are issues with their inputs.
With the Form component injecting react-hook-form 's props into the child component, you can easily create and compose complex forms in your app. Error messages are visual feedback to our users when there are issues with their inputs. React Hook Form provides an errors object to let you retrieve errors easily.
This also causes the component tree to trigger a re-render when React Hook Form triggers a state update, but we can still can optimise our App if required via the example below. React Hook Form embraces uncontrolled components and is also compatible with controlled components.
You could use the hook useFormContext
to avoid to pass the context as a prop https://react-hook-form.com/api/useformcontext
You only need to wrap your form with the FormProvider
component so that you can get context using useFormContext
in your nested component
export default function TestComponent() {
const methods = useForm();
const { register, handleSubmit, errors } = methods;
const onSubmit = data => console.log(data);
return (
<FormProvider {...methods} > // pass all methods into the context
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="name">Name</label>
<input type="text" id="name" name="name" ref={register({ required: true, maxLength: 30 })} />
{errors.name && errors.name.type === "required" && <span>This is required</span>}
{errors.name && errors.name.type === "maxLength" && <span>Max length exceeded</span> }
<NestedComponent1 />
<input type="submit" />
</form>
</FormProvider>
);
}
function NestedComponent1() {
const { register } = useFormContext(); // retrieve all hook methods
return (
<div>
<input {...register("nestedName")} type="text" id="nested-name" name="nestedName" />
<input {...register("nestedName2")} type="text" id="nested-name2" name="nestedName2" />
<input {...register("nestedName3")} type="text" id="nested-name3" name="nestedName3" />
</div>
);
}
To extract your data from the nested components you can add "useState" in your TestComponent and pass down an onChange function to the nested components.
import React from "react";
import { useForm } from "react-hook-form";
export default function App() {
const { register, handleSubmit, errors } = useForm();
const onSubmit = (data) => console.log(data);
return (
<form onSubmit={handleSubmit(onSubmit)}>
<label htmlFor="name">A</label>
<input
type="text"
id="name"
name="name"
ref={register({ required: true, maxLength: 30 })}
/>
{errors.name && errors.name.type === "required" && (
<span>This is required</span>
)}
{errors.name && errors.name.type === "maxLength" && (
<span>Max length exceeded</span>
)}
<NestedComponent1 register={register} />
<NestedComponent2 register={register} />
<input type="submit" />
</form>
);
}
function NestedComponent1({register}) {
return (
<div style={{ display: "flex", flexDirection: "column" }}>
<label htmlFor="nestedName">B</label>
<input type="text" id="nested-name" name="nestedName" ref={register} />
<label htmlFor="nesteNamename2">C</label>
<input type="text" id="nested-name2" name="nestedName2" ref={register} />
<label htmlFor="nestedName3">D</label>
<input type="text" id="nested-name3" name="nestedName3" ref={register} />
</div>
);
}
function NestedComponent2({ register }) {
return (
<div style={{ display: "flex", flexDirection: "column" }}>
<label htmlFor="nestedcomp2Name">E</label>
<input
type="text"
id="nested-comp2-name"
name="nestedcomp2Name"
ref={register}
/>
<label htmlFor="nestedcomp2Name2">F</label>
<input
type="text"
id="nested-comp2-name2"
name="nestedcomp2Name2"
ref={register}
/>
<label htmlFor="nestedcomp2Name3">G</label>
<input
type="text"
id="nested-comp2-name3"
name="nestedcomp2Name3"
ref={register}
/>
</div>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With