简体   繁体   中英

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

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.

Try this out:

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

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM