Как лучше управлять состоянием формы с множеством полей в frontend
Что проверяют
Знаете ли вы, почему большая форма на useState начинает тормозить и как это лечится. Интервьюер ждёт сравнения контролируемого и неконтролируемого подходов. Следом спрашивают про динамические поля, вложенные объекты и валидацию.
Как отвечать
Покажите, что выбор зависит от размера и сложности формы:
- пара полей: хватает
useStateс объектом илиuseReducer. Обработчик один, поле определяется по атрибутуname, обновление через функциюsetForm(prev => ({ ...prev, [name]: value })); - десятки полей: при контролируемом подходе каждое нажатие клавиши перерисовывает всю форму. React Hook Form строится на неконтролируемых полях и
ref, поэтому ввод в одно поле не трогает остальные, а подписка на значения точечная, черезuseWatchилиuseFormState; - Formik: заслуженная, но контролируемая библиотека, на больших формах ре-рендеров больше, и развивается она медленно. В новых проектах чаще выбирают React Hook Form или TanStack Form;
- динамические списки: адреса, телефоны, позиции заказа. В RHF это
useFieldArray, а ключом служит сгенерированныйid, не индекс; - валидация: одна схема Zod или Yup через резолвер, типы формы выводятся из неё же;
- многошаговая форма: общее состояние в одном
useForm, шаги получают его черезFormProviderиuseFormContext.
Отдельно скажите, где форме не место: глобальный стор вроде Redux для черновика почти всегда лишний. Исключение, когда черновик должен пережить уход со страницы: тогда его сохраняют в localStorage или на сервер с debounce.
В React 19 для простых форм есть путь без библиотек: <form action={...}>, useActionState и useFormStatus. Значения читаются из FormData, состояние полей держит сам DOM.
Где спотыкаются
Заводят отдельный useState на каждое поле. На тридцати полях это тридцать сеттеров и копипаста обработчиков.
Лечат тормоза через React.memo и useCallback, не меняя подход. Пока значения формы живут в корневом состоянии, мемоизация спасает мало.
Используют индекс массива как key в динамическом списке. После удаления строки введённые значения съезжают на соседние поля.