У меня есть дочерний компонент ввода и родитель, где я устанавливаю значение.
Родительский компонент
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)}
/>
)
Дочерний компонент ввода
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
Я хочу добавить кнопку в дочерний компонент, где при нажатии мне нужно очистить значение.
Дело в том, что я хочу иметь четкую функциональность в дочернем компоненте и не хочу писать лишний код для каждого <Input в родительском, и что бы я ни делал в дочернем компоненте, я просто не могу переопределить props.value.
У кого-нибудь есть опыт, как это решить?
@RubenSmn Я обновил свой код. Tnx
Если вы хотите очистить входное значение, вы можете передать функцию очистки в качестве реквизита дочернему компоненту следующим образом:
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>
);
}
Поскольку у вас будет разное состояние для каждого входа, вы можете передать функцию set
из useState
в качестве параметра и запустить ее внутри onClearInputHandler
, чтобы очистить значение.
Редактировать:
Тогда я думаю, что самое простое решение — обработать функцию clear
внутри самого ввода следующим образом:
const Input = (props) => {
const [value, setValue] = useState(props.value || '');
return (
<div style = {{ display: 'flex', gap: '.5rem' }}>
<input
{...props}
value = {value}
onChange = {(event) => setValue(event.target.value)}
/>
<button onClick = {() => setValue('')}>Clear</button>
</div>
);
};
export default function App() {
const onSubmitHandler = (event) => {
event.preventDefault();
const formData = new FormData(event.target);
const formProps = Object.fromEntries(formData);
console.info(formProps);
};
return (
<form action = "submit" onSubmit = {onSubmitHandler}>
<div style = {{ display: 'flex', flexDirection: 'column', gap: '.5rem' }}>
<Input
id = "first-name"
label = "First name"
type = "text"
placeholder = "Please enter your first name"
name = "first-name"
/>
<Input
id = "second-name"
label = "Second name"
type = "text"
placeholder = "Please enter your second name"
name = "second-name"
/>
</div>
<button type = "submit" style = {{ margin: '.5rem 0' }}>
Submit
</button>
</form>
);
Все входные данные находятся внутри form
, и вы можете прочитать значения при отправке формы. В противном случае вам придется создать новый state
или ref
для каждого отдельного Input
в вашем родительском компоненте. Таким образом, входное значение и обработчик для его очистки всегда находятся внутри компонента Input
.
Вот демо на stackblitz: https://stackblitz.com/edit/react-gnyvav?file=src%2FApp.js
Спасибо за усилия jcobo1. Дело в том, что, как я уже сказал, я хочу иметь четкую функцию внутри дочернего компонента, которая переопределяет props.value. Я хочу избежать написания родительской функции для каждого использования <Input, поскольку очистка является частью базовой «настройки» нашего компонента <Input.
Для этого есть несколько решений, я придумал эти два
Другим решением может быть преобразование onChange
в onValueChange
, которое вместо event
немедленно возвращает value
. Обновил тип и удалил Partial
, так как он выдавал некоторые ошибки.
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>
</>
);
}
);
Проблема в том, что если указан onChange
, он переопределит существующий onChange
. Мы можем решить эту проблему, просто добавив его и передав e
(событие)
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>
</>
);
}
);
Который вы затем можете использовать
<FormInput
id = "first-name"
type = "text"
placeholder = "Please enter your first name"
value = {dummyText}
onValueChange = {setDummyText}
// onChange = {(e) => console.info(e)}
/>
Теперь это не полностью перемещает функциональность в компонент ввода.
Мы деструктурируем функцию onClear
и добавляем ее в onClick
кнопки очистки.
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>
</>
);
}
);
Теперь, чтобы использовать его, вы можете пойти так
<Input
id = "first-name"
onClear = {() => setDummyText("")}
type = "text"
placeholder = "Please enter your first name"
value = {dummyText}
onChange = {(event) => setDummyText(event.target.value)}
/>
Не могли бы вы поделиться своим компонентом
Input
?