Контролируемые компоненты
Контролируемый компонент — это элемент формы, значение которого хранится в состоянии React. React полностью управляет полем.
Базовый пример
function NameInput() {
const [name, setName] = useState('');
return (
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
);
}
Что происходит:
- Пользователь вводит символ
- Срабатывает
onChange setNameобновляет состояние- React перерисовывает компонент
valueустанавливается в новое значение
Зачем контролировать
- Валидация на лету — можно проверить значение сразу
- Форматирование — например, маска телефона
- Программное изменение — очистить поле, установить значение
- Зависимые поля — одно поле зависит от другого
Одно поле
const [email, setEmail] = useState('');
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
Несколько полей
Отдельные состояния:
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
<input value={email} onChange={(e) => setEmail(e.target.value)} />
<input value={password} onChange={(e) => setPassword(e.target.value)} />
Один обработчик через name:
const [form, setForm] = useState({ email: '', password: '' });
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
const { name, value } = e.target;
setForm((f) => ({ ...f, [name]: value }));
}
<input name="email" value={form.email} onChange={handleChange} />
<input name="password" value={form.password} onChange={handleChange} />
Select
const [role, setRole] = useState('user');
<select value={role} onChange={(e) => setRole(e.target.value)}>
<option value="user">Пользователь</option>
<option value="admin">Администратор</option>
<option value="moderator">Модератор</option>
</select>
В отличие от HTML, selected на опции не используется — значение задаётся на select.
Textarea
const [bio, setBio] = useState('');
<textarea value={bio} onChange={(e) => setBio(e.target.value)} />
В React textarea тоже контролируется через value, а не через дочерний текст.
Checkbox
const [agreed, setAgreed] = useState(false);
<input
type="checkbox"
checked={agreed}
onChange={(e) => setAgreed(e.target.checked)}
/>
Для checkbox используется checked и e.target.checked, а не value.
Radio
const [gender, setGender] = useState('male');
<label>
<input
type="radio"
value="male"
checked={gender === 'male'}
onChange={(e) => setGender(e.target.value)}
/>
Мужской
</label>
<label>
<input
type="radio"
value="female"
checked={gender === 'female'}
onChange={(e) => setGender(e.target.value)}
/>
Женский
</label>
Множественный select
const [tags, setTags] = useState<string[]>([]);
<select
multiple
value={tags}
onChange={(e) => setTags(
Array.from(e.target.selectedOptions, (o) => o.value)
)}
>
<option value="js">JavaScript</option>
<option value="ts">TypeScript</option>
<option value="react">React</option>
</select>
Массив чекбоксов
const [selected, setSelected] = useState<number[]>([]);
function toggle(id: number) {
setSelected((s) =>
s.includes(id) ? s.filter((i) => i !== id) : [...s, id]
);
}
{items.map((item) => (
<label key={item.id}>
<input
type="checkbox"
checked={selected.includes(item.id)}
onChange={() => toggle(item.id)}
/>
{item.name}
</label>
))}
Предупреждение React
Если поставить value без onChange — React выдаст предупреждение. Поле будет только для чтения.
<input value="только чтение" /> // предупреждение
<input value="только чтение" readOnly /> // ОК
Итоги
- Контролируемое поле —
value+onChange - Checkbox —
checked+e.target.checked - Select —
valueнаselect, не наoption - Textarea —
value, не дочерний текст - Radio —
checkedс условием - Один обработчик на много полей — через
name