Reputation: 377
Good Day,
I have a custom component built with material-ui. Am trying to implement react-hook-form. I am registering the components using React forwardRef. React hook form does fire and displays the errors as expected. But when I enter text into textbox the state updates via useState hook but the react hook form errors object does not pick this up. In other words I cannot submit the form even though I have correct values.
First is the CustomTextbox component.
import React from "react";
import TextField from '@material-ui/core/TextField';
interface Props {
id: string;
label: string,
variant: "filled" | "standard" | "outlined",
value: string,
setValue: React.Dispatch<React.SetStateAction<string>>,
disabled?: boolean
}
const CustomTextBox: React.FC<Props> = React.forwardRef(({id, label, variant, value, setValue,
disabled=false}, ref) => {
const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) => {
setValue(e.currentTarget.value);
}
return (
<TextField id={id} label={label} value={value} variant={variant} onChange={e =>
handleChange(e)} disabled={disabled} inputRef={ref} />
);
})
export default CustomTextBox;
Next is how is use this component with react-hook-form
import { ErrorMessage } from "@hookform/error-message";
import { Subtitle2 } from "@material/react-typography";
import React, { useState } from "react";
import { useForm, SubmitHandler } from "react-hook-form";
import { CustomButton } from "../HtmlComponents/CustomButton";
import CustomTextBox from "../HtmlComponents/CustomTextBox";
const UseComponent: React.FunctionComponent = () => {
const [jobTitle, setJobTitle] = useState("");
type Inputs = {
jobTitle: string
}
const { register, handleSubmit, watch, formState: { errors } } = useForm<Inputs>();
const onSubmit: SubmitHandler<Inputs> = data => console.log(data);
useEffect(() => {
console.log(jobTitle);
}, [jobTitle])
return(
<form onSubmit={handleSubmit(onSubmit)}>
<CustomTextBox id="jobTitle" variant="filled" label="Given Names *" value={jobTitle}
setValue={setJobTitle} {...register("jobTitle", {required: "Job title is required"})} />
<ErrorMessage errors={errors} name="jobTitle" render={({ message }) => <Subtitle2 style=
{{color: "red"}}>{message}</Subtitle2>} />
<CustomButton id="submit" label="Save" variant="contained" submit={true}
disabled={false} />
</form>
)
}
export default UseComponent
This is obviously not the entire page but just a single example of trying to re-use the custom component with react-hook-form.
When I submit the error message gets displayed which is expected but I also expect the error to disappear when I enter text in the textbox.
Also please note that the useEffect on jobTile does fire and it gets console logged whenever I type in the textbox. So that measns the useState function passed to custome component does fire and updates the state.
The problem I have is that react-hook-form does not pickup this state change and hence the errors remain.
I'm pretty sure im doing something but I cant pick it up. I appreciate any and all help give.
Thanks and Hello from South Africa.
Upvotes: 4
Views: 16750
Reputation: 286
You have to use Controller
when working with Material-UI and react-hook-form.
References:
Edit:
If you use Controller
then your child component should look like this
interface Props {
id: string;
label: string,
variant: "filled" | "standard" | "outlined",
disabled?: boolean
control:UseControllerProps['control'] // Control prop to pass from Parent Component
name:string // name of field to register with react hook form
}
const CustomTextBox: React.FC<Props> = (
({id, label, variant, disabled=false, control, name}) => {
const { field } = useController({name, control});
// This is not required. React Hook Form will handle onChange events
// const handleChange = (e: React.ChangeEvent<HTMLTextAreaElement | //HTMLInputElement>) =>
// { setValue(e.currentTarget.value);}
return (
<TextField
id={id}
label={label}
variant={variant}
disabled={disabled}
{...field}
/>
}
/>
);
})
In your Parent component, destructure control
from useForm
hook
const { handleSubmit, watch, formState: { errors }, control } = useForm<Inputs>();
UseController Documentation : https://react-hook-form.com/api/usecontroller
Upvotes: 5