I want to create a form by using react-hook-form, but I am having trouble with it. As I found, there was a big change at v7 so the code I used as a reference is not working. I tried to modify it, and I figured out the problem is with the registering, but I cannot pass that name parameter dynamically.
My main component.
import React from 'react';
import i18next from 'i18next';
import { Button, Grid, Typography } from '@material-ui/core';
import { useForm, FormProvider } from 'react-hook-form';
import { Link } from 'react-router-dom';
import FormInput from './CustomTextField'
const AddressForm = ({ next }) => {
const methods = useForm();
return (
<>
<Typography variant="h6" gutterBottom>
{i18next.t('shipping_address')}
</Typography>
<FormProvider {...methods}>
<form onSubmit={methods.handleSubmit((data) => {
console.log(data);
next({ ...data })})}>
<Grid container spacing={3}>
<FormInput required register={methods.register} name='lastName' label={i18next.t('last_name')} />
<FormInput required register={methods.register} name='firstName' label={i18next.t('first_name')} />
<FormInput required register={methods.register} name='email' label={i18next.t('mail')} />
<FormInput required register={methods.register} name='zip' label={i18next.t('zip_code')} />
<FormInput required register={methods.register} name='city' label={i18next.t('city')} />
<FormInput required register={methods.register} name='address1' label={i18next.t('address_1')} />
</Grid>
<br />
<div style={{ display: 'flex', justifyContent: 'space-between' }}>
<Button component={Link} to="/cart" variant="outlined">
{i18next.t('back_to_cart')}
</Button>
<Button type="submit" variant="contained" color="primary">
{i18next.t('next_step')}
</Button>
</div>
</form>
</FormProvider>
</>
)
}
export default AddressForm
CustomTextField component:
import React from 'react';
import { TextField, Grid } from '@material-ui/core';
import { useFormContext, Controller } from 'react-hook-form';
const CustomTextField = ({ name, label, register, required}) => {
const { control } = useFormContext();
return (
<Grid item xs={12} sm={6}>
<Controller
control={control}
name={name}
render = {(field) => (
<TextField
{...register({name})} // <--- It is not working like this
label={label}
required={required}
/>
)}
/>
</Grid>
)
}
export default CustomTextField
By the doc: https://react-hook-form.com/api/useform/register
it takes the input field's name as a parameter, if I pass it in as a string, it works fine. How can I pass the name's value as a parameter to the register() function?
CodePudding user response:
The problem is you're mixing RHF's <Controller /> and register. As Mui's <TextField /> is an external controlled component you should use <Controller />. Check the docs here for more info.
const CustomTextField = ({ name, label, register, required}) => {
const { control } = useFormContext();
return (
<Grid item xs={12} sm={6}>
<Controller
control={control}
name={name}
render={({ field: { ref, ...field } }) => (
<TextField
{...field}
inputRef={ref}
label={label}
required={required}
/>
)}
/>
</Grid>
)
}
If you really want to use register here, you have to remove the wrapping <Controller /> and pass a name as a string instead as an object like you are doing right now. But i would recommend to use <Controller /> as with register you are losing the functionality of setting up the correct ref for your <TextField /> input element as it is linked via the inputRef prop instead of using ref which RHF register uses.
const CustomTextField = ({ name, label, register, required}) => {
const { control } = useFormContext();
return (
<Grid item xs={12} sm={6}>
<TextField
{...register(name)}
label={label}
required={required}
/>
</Grid>
)
}
