Перейти к основному содержимому

FormArray

Headless compound component для управления массивами форм.

Базовое использование

import { FormArray } from '@reformer/ui/form-array';

<FormArray.Root control={form.items}>
<FormArray.Empty>
<p>Нет элементов</p>
</FormArray.Empty>

<FormArray.List>
{({ control, index, remove }) => (
<div key={control.id}>
<h4>Элемент #{index + 1}</h4>
<ItemForm control={control} />
<button onClick={remove}>Удалить</button>
</div>
)}
</FormArray.List>

<FormArray.AddButton>Добавить</FormArray.AddButton>
</FormArray.Root>

Sub-компоненты

КомпонентPropsНазначение
FormArray.Rootcontrol: ArrayNode<T>Context provider
FormArray.Listchildren: (item) => ReactNodeИтерация по элементам (render props)
FormArray.AddButtoninitialValue?: Partial<T>Добавляет новый элемент
FormArray.RemoveButton-Удаляет текущий элемент (внутри List)
FormArray.Emptychildren: ReactNodeПоказывает при пустом массиве
FormArray.Countrender?: (count) => ReactNodeОтображает количество
FormArray.ItemIndexrender?: (index) => ReactNodeОтображает текущий индекс

Render Props в List

interface FormArrayItemRenderProps<T> {
control: GroupNodeWithControls<T>; // Контрол элемента
index: number; // Индекс (0-based)
id: string | number; // Уникальный ключ
remove: () => void; // Удалить этот элемент
}

Внешнее управление через Ref

import { useRef } from 'react';
import { FormArray, FormArrayHandle } from '@reformer/ui/form-array';

const arrayRef = useRef<FormArrayHandle<ItemType>>(null);

// Управление извне
arrayRef.current?.add({ name: 'New' });
arrayRef.current?.removeAt(0);
arrayRef.current?.clear();

<FormArray.Root ref={arrayRef} control={form.items}>
...
</FormArray.Root>

FormArrayHandle API

interface FormArrayHandle<T> {
add: (value?: Partial<T>) => void;
clear: () => void;
insert: (index: number, value?: Partial<T>) => void;
removeAt: (index: number) => void;
length: number;
isEmpty: boolean;
at: (index: number) => GroupNodeWithControls<T> | undefined;
}

useFormArray Hook

Для полной кастомизации без compound components:

import { useFormArray } from '@reformer/ui/form-array';

function CustomList() {
const { items, add, isEmpty, length } = useFormArray(form.items);

return (
<div>
<span>Всего: {length}</span>
{items.map(({ control, id, remove }) => (
<div key={id}>
<ItemForm control={control} />
<button onClick={remove}>X</button>
</div>
))}
{isEmpty && <p>Пусто</p>}
<button onClick={() => add()}>Добавить</button>
</div>
);
}

Примеры

С кастомным контейнером

<FormArray.List className="space-y-4" as="ul">
{(item) => (
<li>
<ItemForm control={item.control} />
</li>
)}
</FormArray.List>

С начальными значениями

<FormArray.AddButton initialValue={{ status: 'draft', priority: 'low' }}>
Добавить черновик
</FormArray.AddButton>

С счётчиком

<h3>
Элементы (
<FormArray.Count render={(count) =>
count === 0 ? 'нет' : `${count} шт.`
} />
)
</h3>