Jaime Salazar
Jaime Salazar

Reputation: 371

In React hook, no e.target in handleChange with setValue()

Since I'm learning how to build React forms with hooks, I went through the 3 quicks posts that culminate with this one. Everything is going well until I get to the last step when you create your custom hook with:

function useFormInput(initialValue) {
  const [value, setValue] = useState(initialValue);

  function handleChange(e) {
    setValue(e.target.value);
  }

  return {
    value,
    onChange: handleChange
  };
}

The Input is:

const Input = ({ type, name, onChange, value, ...rest }) => (
    <input
        name={name}
        type={type}
        value={value}
        onChange={event => {
            event.preventDefault();
            onChange(name, event.target.value);
        }}
        {...rest}
    />
);

And the Form is:

const Form = () => {
  const email = useFormInput("");
  const password = useFormInput("");

  return (
    <form
      onSubmit={e =>
        e.preventDefault() || alert(email.value) || alert(password.value)
      }
    >
      <Input 
        name="email" 
        placeholder="e-mail" 
        type="email" 
        {...email} 
      />
      <Input
        name="password"
        placeholder="password"
        type="password"
        {...password}
      />
      <input type="submit" />
    </form>
  );
};

So in useFormInput() Chrome complains about

TypeError: Cannot read property ‘value’ of undefined at handleChange

which I'm pretty sure is pointing me to

function handleChange(e) {
  setValue(e.target.value);
}

If I console.log(e) I get 'email', as expected (I think?), but if I try console.log(e.target) I get undefined. So obviously e.target.value doesn't exist. I can get it working by just using

setValue(document.getElementsByName(e)[0].value);

but I don't know what kind of issues this might have. Is this a good idea? Are there drawbacks to getting it to work this way?

Thanks

Upvotes: 0

Views: 25479

Answers (3)

xtealer
xtealer

Reputation: 133

Had this issue with a calendar picker library react-date-picker using Register API. Looking at the documentation found out that there's another way of handling components that don't return the original event object on the onChange function using the Controller API.

More details on Controller API Docs

Example:

/*
* React Function Component Example
* This works with either useForm & useFormContext hooks.
*/
import { FC } from 'react'
import { Controller, useFormContext } from 'react-hook-form'
import DatePicker,{ DatePickerProps } from 'react-date-picker/dist/entry.nostyle'


const FormDateInput: FC<Omit<DatePickerProps, 'onChange'>> = ({
  name,
  ...props
}) => {
  const formMethods = useFormContext()
  const { control } = formMethods ?? {}

  return (
    <Controller
      render={({ field }) => <DatePicker {...props} {...field} />}
      name={name ?? 'date'}
      control={control}
    />
  )
}

export default FormDateInput

Upvotes: 0

Hunter
Hunter

Reputation: 3362

Try this out:

const handleChange = e => {
   const { inputValue } = e.target;
   const newValue = +inputValue;
   setValue(newLimit);
};

Upvotes: 0

Mohamed Ramrami
Mohamed Ramrami

Reputation: 12691

The issue comes from the onChange prop in the Input component

    onChange={event => {
        event.preventDefault();
        onChange(name, event.target.value);
    }}

you're calling onChange like this onChange(name, event.target.value); (two arguments, the first one is a string), while in your custom hook you define the callback like this

  function handleChange(e) {
    setValue(e.target.value);
  }

it's expecting one argument, an event.

So either call onChange with one argument (the event) :

onChange={event => {
    event.preventDefault();
    onChange(event);
}}

or change the implementation of the callback.

Upvotes: 5

Related Questions