Reputation: 123
Hi im trying to do one form with react-hook-form and material-ui. I don't want to write Controller every time for all TextFields. Because of that i declare it in another file and call it in my form but its not working i didn't understand why, because in some videos that i watched is working. What is the problem and how i can fix it ?
Form Field
import React from 'react'
import { TextField, Grid } from '@material-ui/core'
import { useForm, Controller, useFormContext } from 'react-hook-form'
const FormField = ({name, label}) => {
const { control } = useForm()
return (
<Grid item xs={12} sm={6} >
<Controller
render = {({field}) =>
<TextField
{...field}
label={label} required
/>}
name={name}
control = {control}
defaultValue=""
/>
</Grid>
)
}
export default FormField
Adress Form
import React from 'react'
import { InputLabel, Select, MenuItem, Button, Grid, Typography, TextField } from '@material-ui/core'
import { useForm, FormProvider, Controller } from 'react-hook-form'
import FormField from './FormField'
import { Link } from 'react-router-dom'
const AdressForm = ({next}) => {
const {handleSubmit, control} = useForm()
return (
<>
<Typography variant="h6" gutterBottom>Shipping Address </Typography>
<form onSubmit={handleSubmit((data) => console.log(data) )}>
<Grid container spacing={3}>
<FormField name='firstName' label='First Name' required='required'/>
<FormField name='lastName' label='Last Name' />
<FormField name='email' label='Email' />
<FormField name='phoneNumber' label='Phone Number' />
</Grid>
<br/>
<div style={{ display: 'flex', justifyContent: 'space-between'}}>
<Button component={Link} to="/cart" variant="outlined">Back to Cart</Button>
<Button type="submit" variant="contained" color="primary">Next</Button>
</div>
</form>
</>
)
}
export default AdressForm
Upvotes: 3
Views: 8024
Reputation: 81310
You must use one useForm
hook for each form, in your code, you call useForm
in every Field
components, creating multiple independent form states, which leads to unexpected result.
What you need to do is to call useForm
in the parent element and pass the dependencies (register
, formState
, error
...) down the child components, so your form can have one unified state. If you have a deeply nested components, you can use useFormContext
to pass the form context to the nested children easily:
import React from "react";
import { useForm, FormProvider, useFormContext } from "react-hook-form";
export default function App() {
const methods = useForm();
const onSubmit = data => console.log(data);
return (
<FormProvider {...methods} > // pass all methods into the context
<form onSubmit={methods.handleSubmit(onSubmit)}>
<NestedInput />
<input type="submit" />
</form>
</FormProvider>
);
}
function NestedInput() {
const { register } = useFormContext(); // retrieve all hook methods
return <input {...register("test")} />;
}
Upvotes: 5