1

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 2

3

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} />
Sign up to request clarification or add additional context in comments.

1 Comment

I am using formik + react-select. This solved my issue too. Very clever
0

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

1 Comment

Hi Rasoul, welcome to Stack Overflow. I have hard time understanding your answer. Would you mind editing it and use proper formatting? stackoverflow.com/editing-help#comment-formatting

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.