Controlled формы
Тема дорожной карты · React
Контролируемые формы в React — это формы, в которых значение каждого поля ввода управляется состоянием компонента через useState или useReducer, делая React единственным источником истины для данных формы. В контролируемой форме каждый элемент <input>, <select> или <textarea> получает проп value, привязанный к состоянию, и обработчик onChange, обновляющий это состояние при каждом нажатии клавиши. Такой подход позволяет React-разработчикам выполнять валидацию в реальном времени, условный рендеринг полей и программную отправку без прямого обращения к DOM. Контролируемые формы противопоставляются неконтролируемым формам, которые используют useRef для императивного чтения значений, и являются рекомендованным паттерном для сложных многопольных форм в React. Библиотеки вроде React Hook Form оптимизируют производительность контролируемых форм, минимизируя перерендеры и сохраняя привычную для React-разработчиков модель контролируемых полей.
Как это работает
Controlled формы использует camelCase event props (onClick, onChange, onSubmit), получающие SyntheticEvent — кроссбраузерную обёртку React над нативным событием. Для форм: "controlled"-компоненты держат значение input в state и ререндерятся на change; "uncontrolled" читают значение через ref при необходимости. useRef возвращает мутируемый контейнер (.current), переживающий рендеры без триггера ререндера — полезно для DOM-узлов и uncontrolled-инпутов.
Когда применять
Controlled-формы — когда (а) нужна валидация по мере ввода, (б) UI зависит от form state (live preview, условные поля), (в) сабмит через fetch с полным контролем. Uncontrolled — когда форма большая + простая (DOM хранит значения, читаете через FormData на сабмит). Для нетривиальных форм — react-hook-form: избегает ререндера на каждое нажатие в полностью controlled-формах.
Типичные ошибки
Ловушки Controlled формы: забытый preventDefault() на сабмите формы — браузер перезагружается; бинд событий на элементах, которые их не генерируют (onClick на <div> без keyboard support = недоступно); хранение каждого нажатия в state на 50-полевой форме (rerender-шторм); использование ref.current внутри render (refs не реактивны — изменения не триггерят ререндер). useRef — escape hatch, не обычный state.