Home > Mobile >  Override input value in Child component in React
Override input value in Child component in React

Time:02-05

I have a child input component and parent where I set value.

Parent component

const \[dummyText, setDummyText\] = useState('')
return (

<Input
  {...props}
  id="first-name"
  label="First name"
  type="text"
  placeholder="Please enter your first name"
  value={dummyText}
  onChange={(value) => setDummyText(value.target.value)}
/>
)

Child input component

    import React, { InputHTMLAttributes, forwardRef } from 'react'
    export type Props = {} & InputHTMLAttributes<HTMLInputElement>

    const FormInput: React.FC<Props> = forwardRef<HTMLInputElement, Partial<Props>>(
      ({ ...props }, ref) => <input ref={ref} {...props} />
    )

    FormInput.displayName = 'FormInput'

    export default FormInput

I want to add button in child component where on click I need to clear the value.

The thing is that I want to have clear functionality in child component and I do not want to write extra code for every <Input in parent, and whatever I do in child component, I just can't override props.value.

Does anybody have any experience how to solve this?

CodePudding user response:

If you want to clear the input value you can pass the clearing function as a prop to the child component like this:

const Input = ({ onClearInput, ...otherProps }) => {
  return (
    <div style={{ display: 'flex', gap: '.5rem' }}>
      <input {...otherProps} />
      <button onClick={onClearInput}>Clear</button>
    </div>
  );
};

export default function App() {
  const [firstName, setFirstName] = useState('');
  const [secondName, setSecondName] = useState('');

  const onClearInputHandler = (handler) => handler('');

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '.5rem' }}>
      <Input
        id="first-name"
        label="First name"
        type="text"
        placeholder="Please enter your first name"
        value={firstName}
        onChange={(event) => setFirstName(event.target.value)}
        onClearInput={() => onClearInputHandler(setFirstName)}
      />

      <Input
        id="second-name"
        label="Second name"
        type="text"
        placeholder="Please enter your second name"
        value={secondName}
        onChange={(event) => setSecondName(event.target.value)}
        onClearInput={() => onClearInputHandler(setSecondName)}
      />
    </div>
  );
}

Because you'll have a different state for each input you can pass the set function from useState as a parameter and run it inside the onClearInputHandler to clear the value.

CodePudding user response:

There are a few solutions for this, I came up with these two

onValueChange

Another solution might be to refactor the onChange to a onValueChange which instead of the event immediately returns the value. Updated the type and removed the Partial since it was giving some errors.

type Props = {
  onValueChange: (value: string) => void;
} & InputHTMLAttributes<HTMLInputElement>;

const FormInput: React.FC<Props> = forwardRef<HTMLInputElement, Props>(
  ({ onValueChange, ...props }, ref) => {
    return (
      <>
        <input
          ref={ref}
          onChange={(e) => onValueChange(e.target.value)}
          {...props}
        />
        <button onClick={() => onValueChange("")}>clear</button>
      </>
    );
  }
);

A issue with this is that if a onChange is provided it will override the existing onChange. We can solve this by simply adding it and passing the e (event)

const FormInput: React.FC<Props> = forwardRef<HTMLInputElement, Props>(
  ({ onValueChange, onChange, ...props }, ref) => {
    return (
      <>
        <input
          ref={ref}
          onChange={(e) => {
            onValueChange(e.target.value);
            onChange(e);
          }}
          {...props}
        />
        <button onClick={() => onValueChange("")}>clear</button>
      </>
    );
  }
);

Which you can then use by

<FormInput
  id="first-name"
  type="text"
  placeholder="Please enter your first name"
  value={dummyText}
  onValueChange={setDummyText}
  // onChange={(e) => console.log(e)}
/>

onClear

Now this does not fully move the functionality to the Input component.

We destructure the onClear function and add it to the onClick of the clear button.

type Props = { onClear: () => void } & InputHTMLAttributes<HTMLInputElement>;

const FormInput: React.FC<Props> = forwardRef<HTMLInputElement, Props>(
  ({ onClear, ...props }, ref) => {
    return (
      <>
        <input ref={ref} {...props} />
        <button onClick={onClear}>clear</button>
      </>
    );
  }
);

Now to use it you can go like this

<Input
  id="first-name"
  onClear={() => setDummyText("")}
  type="text"
  placeholder="Please enter your first name"
  value={dummyText}
  onChange={(event) => setDummyText(event.target.value)}
/>
  • Related