Reputation: 367
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;
Upvotes: 1
Views: 2692
Reputation: 1
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
Upvotes: 0
Reputation: 2613
The react-select
library is not returning the actual input element, which is what react-hook-form
relies on. You can resolve the problem using a pseudo event like this:
let pseudoEvent = { target: { name: "role", value: event.value } };
onChange(pseudoEvent);
To better understand what react-select does with a normal <input />
, intercept your email
input onChange and analyze the event.
const emailHandler = register('email');
const onEmailChange = (event: any) => {
console.log(event);
}
<input type="email" {...emailHandler} onChange={onEmailChange} />
Upvotes: 3