'Custom onChange for React Hook Form and watch()

I am trying to write a custom onChange and watch the change.

Error:

The watched myValue does not register the changes in the dropdown. Any ideas why?

According to the API documentation, this is possible by doing the following:

export default function App() {
  const { register, watch } = useForm();

  const fruits = register("fruits");

  const myValue = watch("fruits", "default");

  return (
    <div className="App">
      <h1>{myValue}</h1>
      <select
        onChange={(e) => {
          fruits.onChange(e); // react hook form onChange
          console.log("Here would go the my onChange"); // my onChange
        }}
        onBlur={fruits.onBlur}
        ref={fruits.ref}
      >
        <option value="1Banana">Banana</option>
        <option value="1Kiwi">Kiwi</option>
        <option value="1Mango">Mango</option>
      </select>
    </div>
  );
}

You may find the upper example here:

https://codesandbox.io/s/divine-rgb-mwiqn?file=/src/App.js



Solution 1:[1]

You are not passing the name prop to your select. The documentation is saying you should be doing this by default:

<select {...register('fruits')}>

If you log what register('fruits') return you'll see a name prop in there besides onChange, onBlur and ref. If you add name={fruits.name} to your select you'll see watch working too.

Edit: yes, this is missing from the documentation too at the moment.

Solution 2:[2]

You forgot to pass register() props to Component. By passing {...fruits} on select, it is working.

export default function App() {
  const { register, watch } = useForm();

  const fruits = register("fruits");

  const myValue = watch("fruits", "default");

  return (
    <div className="App">
      <h1>{myValue}</h1>
      <select
        onChange={(e) => {
          fruits.onChange(e); // react hook form onChange
          console.log("Here would go the my onChange"); // my onChange
        }}
        {...register('fruits')}
        onBlur={fruits.onBlur}
        ref={fruits.ref}
      >
        <option value="1Banana">Banana</option>
        <option value="1Kiwi">Kiwi</option>
        <option value="1Mango">Mango</option>
      </select>
    </div>
  );
}

Solution 3:[3]

With a useState hook it's working link so:

e.target.value is the selected value of your dropdown menu. To change your title dynamically you have to use a hook to serenader your component when the state changes.

See bellow:

import React from 'react';
import { useForm } from "react-hook-form";
import "./styles.css";

export default function App() {
  const { register, watch } = useForm();
  // const myValue = watch("fruits", "default");
  const [myVal, setMyVal] = React.useState('Default')

  const fruits = register("fruits");


  return (
    <div className="App">
      <h1>{myVal}</h1>
      <select
        onChange={(e) => {
          fruits.onChange(e);
          setMyVal(e.target.value); // react hook form onChange
          console.log("Here would go the my onChange"); // my onChange
        }}
        onBlur={fruits.onBlur}
        ref={fruits.ref}
      >
        <option value="1Banana">Banana</option>
        <option value="1Kiwi">Kiwi</option>
        <option value="1Mango">Mango</option>
      </select>
    </div>
  );
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Sergiu Paraschiv
Solution 2 Daryl Wong
Solution 3 GregMit