Что такое controlled и uncontrolled компоненты?
Controlled и Uncontrolled компоненты — это два разных подхода к управлению состоянием формовых элементов (input, textarea, select и т. д.) в React. Они определяют, кто управляет текущим значением поля ввода: сам DOM (в случае uncontrolled) или React (в случае controlled).
Controlled компоненты
Controlled component (контролируемый компонент) — это компонент формы, значение которого полностью контролируется React через состояние (state). Изменение значения происходит только через вызов setState() или хука useState(). React обновляет значение поля в соответствии со значением из state, и форма становится «односторонней» — от состояния к UI.
Признаки:
-
Значение хранится в state
-
Поле имеет атрибут value, привязанный к переменной состояния
-
Любые изменения обрабатываются через обработчик onChange
Пример:
import React, { useState } from 'react';
function ControlledInput() {
const \[value, setValue\] = useState('');
return (
<TextInput
value={value}
onChangeText={text => setValue(text)}
placeholder="Введите имя"
/>
);
}
Особенности:
-
React полностью управляет данными
-
Удобно валидировать, форматировать, модифицировать ввод на лету
-
Гарантированное соответствие данных в компоненте и UI
-
Легче тестировать и обрабатывать сторонние эффекты
Минусы:
-
Большое количество контролируемых компонентов может привести к лишним ререндерам
-
Нужно вручную писать обработчики событий
Uncontrolled компоненты
Uncontrolled component (неконтролируемый компонент) — это компонент, значение которого хранится внутри DOM и извлекается только по необходимости. React не управляет значением такого поля. Это ближе к традиционному подходу JavaScript, где доступ к значению формы осуществляется через ref и методы DOM.
Признаки:
-
Значение хранится в DOM, а не в state
-
Используется defaultValue вместо value
-
Для чтения значения применяется useRef() и ref.current
Пример:
import React, { useRef } from 'react';
import { TextInput, Button } from 'react-native';
function UncontrolledInput() {
const inputRef = useRef(null);
const handlePress = () => {
const value = inputRef.current?.value || inputRef.current?.\_lastNativeText;
console.log('Введено:', value);
};
return (
<>
<TextInput
ref={inputRef}
defaultValue="Привет"
placeholder="Введите что-нибудь"
/>
<Button title="Считать" onPress={handlePress} />
</>
);
}
Особенности:
-
Значение доступно через ref, а не state
-
Подходит для простых или быстро изменяемых форм
-
Чтение значения по событию, а не каждый рендер
-
Меньше кода при больших формах
Минусы:
-
Сложнее отслеживать изменения
-
Ограниченные возможности для валидации в реальном времени
-
Меньше контроль со стороны React
Сравнение Controlled vs Uncontrolled
Характеристика | Controlled | Uncontrolled |
---|---|---|
Хранение значения | React state | DOM (через ref) |
--- | --- | --- |
Управление | React управляет | Компонент управляет сам |
--- | --- | --- |
Обновление | Через setState() | Через прямое обращение к DOM |
--- | --- | --- |
Атрибут для значения | value | defaultValue |
--- | --- | --- |
Чтение значения | В каждый момент | Только при необходимости |
--- | --- | --- |
Подходит для | Валидация, форматирование, фильтры | Простые формы, быстрая инициализация |
--- | --- | --- |
Использование с React Hook Form | Требует обёртки | Поддерживается напрямую |
--- | --- | --- |
Когда использовать controlled компоненты
-
Требуется немедленная валидация или фильтрация текста
-
Нужно реализовать автосохранение или отображение состояния в UI
-
Нужно точно знать и контролировать значение
-
Значение используется в других частях компонента или влияет на рендер
-
Необходимо синхронизировать несколько полей формы
Когда использовать uncontrolled компоненты
-
Формы с большим числом полей, где не требуется контроль над каждым полем
-
Быстрое создание формы без необходимости проверки значений на лету
-
Интеграция с нативными библиотеками, сторонними UI-компонентами
-
Значение требуется только при отправке формы (submit)
Смешанный подход
Иногда можно комбинировать оба подхода: использовать controlled для ключевых полей, а остальные — оставить неконтролируемыми. Также в крупных проектах часто применяют библиотеки, вроде Formik или React Hook Form, которые поддерживают и те и другие компоненты, но реализуют оптимизации для производительности.
import { useForm, Controller } from 'react-hook-form';
function MyForm() {
const { control, handleSubmit } = useForm();
return (
<Controller
control={control}
name="email"
defaultValue=""
render={({ field: { onChange, value } }) => (
<TextInput
value={value}
onChangeText={onChange}
placeholder="Email"
/>
)}
/>
);
}
Контролируемые компоненты дают полный контроль и гибкость, в то время как неконтролируемые позволяют быстрее строить простые формы без нагрузки на состояние. Выбор между ними зависит от задач, архитектуры приложения и требований к пользовательскому взаимодействию.