Как реализовать динамическое добавление полей в формах с помощью Formik
Что проверяют
Знаете ли вы FieldArray и его помощники, как устроены имена вложенных полей и как валидировать массив. Часто следом спрашивают про ключи при удалении и про производительность больших форм.
Как отвечать
Каркас такой:
- начальные значения: массив обязательно есть в
initialValues, хотя бы пустой:{ friends: [] }. Иначеvalues.friendsбудетundefined; - FieldArray:
<FieldArray name="friends">отдаёт через render-проп помощникиpush,remove,insert,move,swap,replace,unshift. Добавление:push({ id: crypto.randomUUID(), name: "" }); - имена полей: путь до значения,
friends.${index}.nameилиfriends[${index}].name, Formik понимает обе записи; - ключи: стабильный
idвнутри элемента, а не индекс массива; - валидация:
validationSchemaна Yup, напримерarray().of(object({ name: string().required() })).min(1). Ошибку конкретного поля показываетErrorMessageс тем же путём вname; - кнопки: у «Добавить» и «Удалить» обязательно
type="button", иначе клик отправит форму.
Хорошо показать, что вы знаете контекст. Formik почти не развивается, крупных релизов давно не было, и в новых проектах чаще берут React Hook Form: там то же самое делает useFieldArray, он сам выдаёт field.id для ключей и не перерисовывает всю форму на каждый ввод. У Formik перерисовка всей формы на каждое нажатие клавиши заметна на длинных списках, частично помогает FastField.
Если форму редактируют после загрузки данных с сервера, упомяните enableReinitialize и то, что без него пришедшие данные не попадут в поля.
Где спотыкаются
Ставят key={index}. После удаления второго элемента React переиспользует DOM-узлы, и введённый текст или фокус «переезжает» в соседнюю строку.
Обращаются к errors.friends[index].name без проверки. Ошибка уровня массива, например из min(1), приходит строкой, и такой код падает.
Забывают про touched: ошибки новых пустых полей показываются сразу после нажатия «Добавить», ещё до того, как человек что-то ввёл.