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)}
/>