# Reform Field Arrays

Reform provides comprehensive support for managing array fields within form groups. This document covers the field array capabilities of Reform.

## Table of Contents

- [Overview](#overview)
- [Basic Usage](#basic-usage)
- [Array Operations](#array-operations)
- [Dynamic Arrays](#dynamic-arrays)
- [Validation](#validation)
- [API Reference](#api-reference)

## Overview

Reform's field array system allows you to:

1. **Manage array fields** within form groups
2. **Perform array operations** (append, remove, move, etc.)
3. **Handle validation** for array items
4. **Track changes** in array fields

## Basic Usage

Here's a basic example of using array fields in a form:

```tsx
import { useReform } from '@reform/core';

type UserForm = {
  name: string;
  phones: string[];
  addresses: {
    street: string;
    city: string;
  }[];
};

const UserForm = () => {
  const form = useReform<UserForm>({
    defaultData: {
      name: '',
      phones: [],
      addresses: [],
    },
    minGroups: 1,
  });

  // Add a new phone number
  const handleAddPhone = () => {
    form.append(0, 'phones', '');
  };

  // Add a new address
  const handleAddAddress = () => {
    form.append(0, 'addresses', { street: '', city: '' });
  };

  return (
    <form>
      <input {...form.register(0, 'name')} placeholder="Name" />

      {/* Phone numbers */}
      <div>
        <h3>Phone Numbers</h3>
        {form.getArray(0, 'phones').map((phone, phoneIndex) => (
          <div key={phoneIndex}>
            <input
              {...form.register(0, `phones.${phoneIndex}`)}
              placeholder="Phone number"
            />
            <button
              type="button"
              onClick={() => form.remove(0, 'phones', phoneIndex)}
            >
              Remove
            </button>
          </div>
        ))}
        <button type="button" onClick={handleAddPhone}>
          Add Phone
        </button>
      </div>

      {/* Addresses */}
      <div>
        <h3>Addresses</h3>
        {form.getArray(0, 'addresses').map((address, addressIndex) => (
          <div key={addressIndex}>
            <input
              {...form.register(0, `addresses.${addressIndex}.street`)}
              placeholder="Street"
            />
            <input
              {...form.register(0, `addresses.${addressIndex}.city`)}
              placeholder="City"
            />
            <button
              type="button"
              onClick={() => form.remove(0, 'addresses', addressIndex)}
            >
              Remove
            </button>
          </div>
        ))}
        <button type="button" onClick={handleAddAddress}>
          Add Address
        </button>
      </div>
    </form>
  );
};
```

## Array Operations

Reform provides several operations for managing array fields:

```tsx
// Append an item to the end of the array
form.append(0, 'phones', '555-0123');

// Remove an item at a specific index
form.remove(0, 'phones', 2);

// Update an item at a specific index
form.update(0, 'phones', 1, '555-4567');

// Move an item from one position to another
form.move(0, 'phones', 0, 2);

// Swap two items
form.swap(0, 'phones', 1, 3);

// Insert an item at a specific position
form.insert(0, 'phones', 1, '555-8901');

// Replace the entire array
form.replace(0, 'phones', ['555-0123', '555-4567', '555-8901']);
```

## Dynamic Arrays

Example of a dynamic form with array fields:

```tsx
import { useReform } from '@reform/core';

type EducationForm = {
  schools: {
    name: string;
    degree: string;
    years: {
      from: number;
      to: number;
    }[];
  }[];
};

const EducationForm = () => {
  const form = useReform<EducationForm>({
    defaultData: {
      schools: [],
    },
    minGroups: 1,
  });

  const handleAddSchool = () => {
    form.append(0, 'schools', {
      name: '',
      degree: '',
      years: [],
    });
  };

  const handleAddYear = (schoolIndex: number) => {
    form.append(0, `schools.${schoolIndex}.years`, {
      from: new Date().getFullYear(),
      to: new Date().getFullYear(),
    });
  };

  return (
    <form>
      <h2>Education History</h2>
      {form.getArray(0, 'schools').map((school, schoolIndex) => (
        <div key={schoolIndex} className="school-entry">
          <h3>School {schoolIndex + 1}</h3>
          <input
            {...form.register(0, `schools.${schoolIndex}.name`)}
            placeholder="School name"
          />
          <input
            {...form.register(0, `schools.${schoolIndex}.degree`)}
            placeholder="Degree"
          />

          <div className="years">
            <h4>Years Attended</h4>
            {form.getArray(0, `schools.${schoolIndex}.years`).map((year, yearIndex) => (
              <div key={yearIndex} className="year-entry">
                <input
                  type="number"
                  {...form.register(0, `schools.${schoolIndex}.years.${yearIndex}.from`)}
                  placeholder="From year"
                />
                <input
                  type="number"
                  {...form.register(0, `schools.${schoolIndex}.years.${yearIndex}.to`)}
                  placeholder="To year"
                />
                <button
                  type="button"
                  onClick={() => form.remove(0, `schools.${schoolIndex}.years`, yearIndex)}
                >
                  Remove Year
                </button>
              </div>
            ))}
            <button
              type="button"
              onClick={() => handleAddYear(schoolIndex)}
            >
              Add Year
            </button>
          </div>

          <button
            type="button"
            onClick={() => form.remove(0, 'schools', schoolIndex)}
          >
            Remove School
          </button>
        </div>
      ))}
      <button type="button" onClick={handleAddSchool}>
        Add School
      </button>
    </form>
  );
};
```

## Validation

Example of array field validation:

```tsx
import { useReform } from '@reform/core';
import * as yup from 'yup';

const schema = yup.object({
  phones: yup.array().of(
    yup.string().matches(/^\d{3}-\d{4}$/, 'Invalid phone format (XXX-XXXX)')
  ).min(1, 'At least one phone number is required'),
  addresses: yup.array().of(
    yup.object({
      street: yup.string().required('Street is required'),
      city: yup.string().required('City is required'),
    })
  ).min(1, 'At least one address is required'),
});

const MyForm = () => {
  const form = useReform<UserForm>({
    defaultData: {
      phones: [],
      addresses: [],
    },
    minGroups: 1,
    groupSchema: schema,
  });

  // ... form implementation
};
```

## API Reference

### Field Array Methods

```typescript
interface FieldArrayHelpers<T> {
  getArray<K extends keyof T>(
    index: number,
    field: K
  ): any[];

  append<K extends keyof T>(
    index: number,
    field: K,
    value: any,
    options?: { shouldFocus?: boolean }
  ): void;

  remove<K extends keyof T>(
    index: number,
    field: K,
    arrayIndex: number
  ): void;

  update<K extends keyof T>(
    index: number,
    field: K,
    arrayIndex: number,
    value: any
  ): void;

  move<K extends keyof T>(
    index: number,
    field: K,
    from: number,
    to: number
  ): void;

  swap<K extends keyof T>(
    index: number,
    field: K,
    indexA: number,
    indexB: number
  ): void;

  insert<K extends keyof T>(
    index: number,
    field: K,
    arrayIndex: number,
    value: any
  ): void;

  replace<K extends keyof T>(
    index: number,
    field: K,
    newArray: any[]
  ): void;
}
```

### Method Parameters

| Method | Parameters | Description |
|--------|------------|-------------|
| getArray | `index`: number, `field`: keyof T | Gets the array value for a specific field |
| append | `index`: number, `field`: keyof T, `value`: any, `options?`: { shouldFocus?: boolean } | Adds a new item to the end of the array |
| remove | `index`: number, `field`: keyof T, `arrayIndex`: number | Removes an item at the specified index |
| update | `index`: number, `field`: keyof T, `arrayIndex`: number, `value`: any | Updates an item at the specified index |
| move | `index`: number, `field`: keyof T, `from`: number, `to`: number | Moves an item from one position to another |
| swap | `index`: number, `field`: keyof T, `indexA`: number, `indexB`: number | Swaps two items in the array |
| insert | `index`: number, `field`: keyof T, `arrayIndex`: number, `value`: any | Inserts a new item at the specified position |
| replace | `index`: number, `field`: keyof T, `newArray`: any[] | Replaces the entire array with a new one |