Что такое 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="Введите что-нибудь"
/>
&lt;Button title="Считать" onPress={handlePress} /&gt;
&lt;/&gt;
);
}

Особенности:

  • Значение доступно через 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"
/>
)}
/>
);
}

Контролируемые компоненты дают полный контроль и гибкость, в то время как неконтролируемые позволяют быстрее строить простые формы без нагрузки на состояние. Выбор между ними зависит от задач, архитектуры приложения и требований к пользовательскому взаимодействию.