I cannot find a solution to make react-select and react-hook-form work.
I constantly get an error: Cannot read properties of undefined (reading ‘name’) and an error telling me that my field is required.
Here is my code in codesandbox: https://codesandbox.io/s/funny-elbakyan-h5xz8w?file=/src/App.tsx:0-1347
Below is my code:
// InputSelect.tsx
import React from "react";
import clsx from "clsx";
import { default as ReactSelect, MenuPlacement } from "react-select";
export type SelectOption = {
value: string;
label: string;
key?: string;
};
export type InputSelectProps = {
name: string;
onChange: (value: any) => void;
options: SelectOption[];
error?: string;
};
const InputSelect: React.FC<InputSelectProps> = React.forwardRef(
({ id, options, name, onChange, label = "", error }, ref: React.Ref<any>) => {
const prefix = React.useId();
const inputId = id ?? `${prefix}-${name}`;
const isError = Boolean(error);
const [
selectedOption,
setSelectedOption
] = React.useState<SelectOption | null>(null);
const handleChange = (event: any) => {
console.log(event);
setSelectedOption(event);
// BUG is here - Cannot read properties of undefined (reading 'name')
onChange(event);
};
return (
<div className={clsx("c-form-field")}>
<label
className={clsx("c-form-field__label c-label pb-2.5")}
htmlFor={inputId}
>
{label}
</label>
<ReactSelect
name={name}
options={options}
onChange={(selectedOption) => {
handleChange(selectedOption);
}}
value={selectedOption}
/>
{/* Error messages */}
{isError && <p className="text-danger">{error}</p>}
</div>
);
}
);
export default InputSelect;
// App.tsx
import React from "react";
import { useForm } from "react-hook-form";
import { yupResolver } from "@hookform/resolvers/yup";
import * as Yup from "yup";
import InputSelect from "./InputSelect";
enum OrganizationRole {
ADMIN = "ADMIN",
MANAGER = "MANAGER",
USER = "USER"
}
interface FormData {
email: string;
role: string;
}
const options = Object.values(OrganizationRole).map((role) => ({
value: role,
label: role
}));
const App: React.FC = () => {
const {
handleSubmit,
register,
formState: { errors }
} = useForm<FormData>({
resolver: yupResolver(
Yup.object({
email: Yup.string().email("Invalid email address").required("Required"),
role: Yup.string().required("Required")
})
)
});
const onSubmit = (data: FormData) => {
console.log(data);
};
return (
<form onSubmit={handleSubmit(onSubmit)}>
<div>
<input type="email" {...register("email")} />
{errors.email && <p>Email est requis</p>}
</div>
<div>
<InputSelect
label={"Role"}
error={errors.role?.message}
options={options}
required
{...register("role")}
/>
{errors.role && <p>Rôle est requis</p>}
</div>
<button type="submit">Envoyer</button>
</form>
);
};
export default App;
2
Answers
The
react-select
library is not returning the actual input element, which is whatreact-hook-form
relies on. You can resolve the problem using a pseudo event like this:To better understand what react-select does with a normal
<input />
, intercept youremail
input onChange and analyze the event.react-select onChange return selected object and you react hook form can get that if you use prop like {…other} for your input.
if you want control that manually and call rhf onChange get react hook form all props as name like field and call field.onChange in this format your input didn’t get any correct props