Ant Design (AntD) предоставляет мощный и гибкий механизм для работы с
формами через компонент Form. Одной из часто востребованных
возможностей является поддержка динамических полей,
которые позволяют пользователю добавлять или удалять элементы формы на
лету. Такая функциональность широко применяется в списках адресов,
телефонов, товаров, атрибутов и других повторяющихся структур
данных.
Для создания динамических полей используется компонент
Form.List, который является контейнером
для повторяющихся полей. Он автоматически управляет индексами,
валидацией и состоянием вложенных элементов.
Простейший пример структуры:
import { Form, Input, Button } from 'antd';
import { MinusCircleOutlined, PlusOutlined } from '@ant-design/icons';
<Form name="dynamic_form" autoComplete="off">
<Form.List name="users">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, fieldKey, ...restField }) => (
<Form.Item
key={key}
required={false}
>
<Form.Item
{...restField}
name={[name, 'firstName']}
fieldKey={[fieldKey, 'firstName']}
rules={[{ required: true, message: 'Введите имя' }]}
noStyle
>
<Input placeholder="Имя" style={{ width: '60%' }} />
</Form.Item>
<MinusCircleOutlined onCl ick={() => remove(name)} />
</Form.Item>
))}
<Form.Item>
<Button type="dashed" onCl ick={() => add()} icon={<PlusOutlined />}>
Добавить пользователя
</Button>
</Form.Item>
</>
)}
</Form.List>
</Form>
Ключевые моменты:
Form.List принимает имя поля (name),
которое будет использоваться в объекте формы.fields и методы
add, remove, которые управляют динамическими
элементами.key для корректной
работы React.Динамические поля полностью поддерживают систему валидации Ant
Design. Важно правильно указывать правила валидации через
rules, особенно при вложенных объектах:
<Form.List name="emails">
{(fields, { add, remove }) => (
<>
{fields.map(({ key, name, fieldKey, ...restField }) => (
<Form.Item key={key} required={false}>
<Form.Item
{...restField}
name={[name, 'email']}
fieldKey={[fieldKey, 'email']}
rules={[
{ required: true, message: 'Введите email' },
{ type: 'email', message: 'Неверный формат email' }
]}
noStyle
>
<Input placeholder="Email" style={{ width: '60%' }} />
</Form.Item>
<MinusCircleOutlined onCl ick={() => remove(name)} />
</Form.Item>
))}
<Form.Item>
<Button type="dashed" onCl ick={() => add()} icon={<PlusOutlined />}>
Добавить email
</Button>
</Form.Item>
</>
)}
</Form.List>
Особенность: валидация будет автоматически применяться к каждому добавленному полю. Удаление поля не влияет на валидацию остальных элементов.
Ant Design поддерживает вложенные динамические списки, что позволяет создавать сложные формы, например, список пользователей с несколькими телефонами:
<Form.List name="users">
{(userFields, { add: addUser, remove: removeUser }) => (
<>
{userFields.map(({ key: userKey, name: userName, fieldKey: userFieldKey, ...userRestField }) => (
<div key={userKey} style={{ marginBottom: 20 }}>
<Form.Item
{...userRestField}
name={[userName, 'name']}
fieldKey={[userFieldKey, 'name']}
rules={[{ required: true, message: 'Введите имя' }]}
>
<Input placeholder="Имя пользователя" />
</Form.Item>
<Form.List name={[userName, 'phones']}>
{(phoneFields, { add: addPhone, remove: removePhone }) => (
<>
{phoneFields.map(({ key, name, fieldKey, ...restField }) => (
<Form.Item key={key}>
<Form.Item
{...restField}
name={name}
fieldKey={fieldKey}
rules={[{ required: true, message: 'Введите телефон' }]}
noStyle
>
<Input placeholder="Телефон" style={{ width: '60%' }} />
</Form.Item>
<MinusCircleOutlined onCl ick={() => remove(name)} />
</Form.Item>
))}
<Form.Item>
<Button type="dashed" onCl ick={() => addPhone()} icon={<PlusOutlined />}>
Добавить телефон
</Button>
</Form.Item>
</>
)}
</Form.List>
<MinusCircleOutlined onCl ick={() => removeUser(userName)} />
</div>
))}
<Form.Item>
<Button type="dashed" onCl ick={() => addUser()} icon={<PlusOutlined />}>
Добавить пользователя
</Button>
</Form.Item>
</>
)}
</Form.List>
noStyle позволяет комбинировать вложенные
Form.Item без лишних отступов.Input, Select,
DatePicker и другие можно гибко комбинировать внутри
Form.List.style легко управлять шириной,
отступами и расположением кнопок добавления/удаления элементов.Динамические поля полностью поддерживают свойство
initialValues у Form. Для этого нужно
передавать массив объектов с нужной структурой:
<Form
name="dynamic_initial"
initialValues={{
users: [
{ name: 'Иван', phones: ['+7 123 456 78 90'] },
{ name: 'Мария', phones: ['+7 987 654 32 10'] }
]
}}
>
Ant Design автоматически сгенерирует соответствующее количество полей и заполнит их значениями.
Методы add и remove позволяют
реализовать:
fields.forEach(f => remove(f.name)))add({ name: '', phones: [''] }))При работе с большим количеством динамических полей рекомендуется:
key для каждого элемента,
особенно при рендере массивов.shouldUpdate или React.memo для
вложенных компонентов, чтобы избежать лишнего ререндеринга.react-window.Form.List — основной инструмент для динамических полей
в Ant Design.add и remove обеспечивают полный
контроль над структурой данных.