Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

onChange handler doesn't fire when using custom-component

I'm using Formik for validation in a React app.

Validation is working correctly, but my onChange handler does not fire:

  <Field
    type="text"
    name="name"
    placeholder="First Name"
    component={Input}
    onChange={() => console.log("gfdg")}
  />

Link to Sandbox

Why is this?

like image 576
A7DC Avatar asked Dec 23 '22 23:12

A7DC


2 Answers

Inside Input, the way you have ordered the props passed to your input element means your onChange is being overwritten by Formik's onChange. When you create a Field with a custom component (i.e. Input in your case), Formik passes its FieldProps to the component. FieldProps contains a property field that contains various handlers including onChange.

In your Input component you do this (I've removed the irrelevant props):

<input
    onChange={onChange}
    {...field}
/>

See how your own onChange will just get replaced by Formik's onChange() inside field? To make it clearer ...field is basically causing this to happen:

<input
    onChange={onChange}
    onChange={field.onChange}
    // Other props inside "field".
/>

If you were to reorder those the console message will now appear:

<input
    {...field}
    onChange={onChange}
/>

However now your input won't work now because you do need to call Formik's onChange to let Formik now when your input changes. If you want both a custom onChange event and for your input to work properly you can do it like this:

import React from "react";
import { color, scale } from "./variables";

const Input = React.forwardRef(
  ({ onChange, onKeyPress, placeholder, type, label, field, form }, ref) => (
    <div style={{ display: "flex", flexDirection: "column" }}>
      {label && (
        <label style={{ fontWeight: 700, marginBottom: `${scale.s2}rem` }}>
          {label}
        </label>
      )}
      <input
        {...field}
        ref={ref}
        style={{
          borderRadius: `${scale.s1}rem`,
          border: `1px solid ${color.lightGrey}`,
          padding: `${scale.s3}rem`,
          marginBottom: `${scale.s3}rem`
        }}
        onChange={changeEvent => {
          form.setFieldValue(field.name, changeEvent.target.value);
          onChange(changeEvent.target.value);
        }}
        onKeyPress={onKeyPress}
        placeholder={placeholder ? placeholder : "Type something..."}
        type={type ? type : "text"}
      />
    </div>
  )
);

export default Input;

See it here in action.

Although overall I'm not really sure what you're trying to do. Your form is working fine, you probably don't need a custom onChange but maybe you have some specific use case.

like image 176
Ciarán Tobin Avatar answered Dec 25 '22 23:12

Ciarán Tobin


Let me first make it clear this answer is just for help purpose and I do know that this question has been accepted but I do have some modification for above answer with my version if the above solution doesn't work for anyone

Here onChangeText will return the value of the quantity field

  <Formik
     initialValues={{ product_id: '', quantity: '', amount: '' }}
     onSubmit={(values, actions) => {
        this.submitLogin(values);
     }}

     //some other elements ....
    <Field placeholder='No. of Quantity' name='quantity' component={CustomInputComponent}
        onChangeText={value => {
           console.warn(value); // will get value of quantity
        }}
     />
  />

Outside of your class you can define your component

const CustomInputComponent = ({
   onChangeText,
   field, // { name, value, onChange, onBlur }
   form: { touched, errors, isValid, handleBlur, handleChange, values, setFieldValue }, // also values, setXXXX, handleXXXX, dirty, isValid, status, etc.
   ...props
}) => {
   return (
      <Input {...field} {...props} onBlur={handleBlur(field.name)}
        onChangeText={value => {
           setFieldValue(field.name, value);
           onChangeText(value); // calling custom onChangeText
        }}
     />
   )
}
like image 44
Abhi Burk Avatar answered Dec 26 '22 00:12

Abhi Burk