Управление состоянием формы

React Aria предоставляет набор хуков для создания доступных компонентов пользовательского интерфейса, включая формы. Управление состоянием формы здесь строится на разделении логики состояния и визуального представления. Основным инструментом является хук useFormState, который управляет данными формы, валидацией и взаимодействием с полями.


useFormState: центральный инструмент

Хук useFormState создаёт объект состояния формы:

import { useFormState } from '@react-stately/form';

const formState = useFormState({
  defaultValues: {
    name: '',
    email: ''
  },
  onSubmit: (values) => {
    console.log('Submitted:', values);
  }
});

Ключевые моменты:

  • defaultValues — начальные значения всех полей.
  • onSubmit — функция, вызываемая при успешной отправке.
  • Форму можно расширять динамическими полями, добавляя их в defaultValues или через методы состояния.

formState содержит важные свойства:

  • values — текущие значения полей.
  • setValue(name, value) — метод для изменения конкретного значения.
  • errors — объект ошибок валидации.
  • isSubmitting — флаг отправки формы.

Управление отдельными полями формы

Для полей используется хук useField, который интегрируется с useFormState:

import { useField } from '@react-aria/label';
import { useTextField } from '@react-aria/textfield';

function TextInput({ name, formState }) {
  const { labelProps, fieldProps } = useField({ name }, formState);
  const { inputProps } = useTextField(fieldProps);

  return (
    <label {...labelProps}>
      {name}
      <input {...inputProps} />
    </label>
  );
}

Особенности:

  • useField связывает поле с формой, предоставляя fieldProps и labelProps.
  • fieldProps содержит имя, текущее значение, обработчики событий (onChange, onBlur).
  • labelProps гарантируют корректную доступность для скринридеров.

Валидация и ошибки

React Aria не накладывает строгих правил валидации, но интегрируется с кастомными функциями:

const formState = useFormState({
  defaultValues: { email: '' },
  validation: (values) => {
    const errors = {};
    if (!values.email.includes('@')) {
      errors.email = 'Email должен содержать @';
    }
    return errors;
  },
  onSubmit: (values) => console.log(values)
});

Принципы работы с ошибками:

  • Объект errors хранит ошибки по имени поля.
  • Поля автоматически получают aria-invalid и aria-describedby для уведомления скринридеров.
  • Реактивное обновление ошибок через setValue позволяет отображать ошибки в реальном времени.

Динамические поля и массивы

Для форм с повторяющимися или динамическими элементами используется хук useFieldArray:

import { useFieldArray } from '@react-stately/form';

function TagsForm({ formState }) {
  const { fields, addField, removeField } = useFieldArray('tags', formState);

  return (
    <>
      {fields.map((field, index) => (
        <TextInput key={field.key} name={`tags[${index}]`} formState={formState} />
      ))}
      <button onCl ick={() => addField('')}>Добавить тег</button>
    </>
  );
}

Преимущества:

  • Управление массивами значений без потери контроля над состоянием.
  • Каждое поле автоматически связывается с формой через useField.
  • Простая интеграция с динамическими компонентами.

Сборка формы и обработка отправки

Форма управляется через компонент <form> с обработчиком onSubmit:

function MyForm() {
  const formState = useFormState({
    defaultValues: { name: '', email: '' },
    onSubmit: (values) => console.log(values)
  });

  return (
    <form onSub mit={formState.handleSubmit}>
      <TextInput name="name" formState={formState} />
      <TextInput name="email" formState={formState} />
      <button type="submit" disabled={formState.isSubmitting}>Отправить</button>
    </form>
  );
}

Особенности:

  • formState.handleSubmit выполняет проверку валидации и вызывает onSubmit.
  • isSubmitting предотвращает повторную отправку.
  • Все поля автоматически синхронизированы с состоянием формы.

Интеграция с кастомными компонентами

React Aria позволяет легко подключать нестандартные элементы:

  • Используется useField для привязки состояния и меток.
  • aria-* атрибуты генерируются автоматически.
  • Методы setValue и setError позволяют контролировать значения и ошибки вручную.
function CustomCheckbox({ name, formState }) {
  const { fieldProps } = useField({ name }, formState);

  return (
    <div role="checkbox"
         aria-checked={formState.values[name]}
         onCl ick={() => formState.setValue(name, !formState.values[name])}>
      {name}
    </div>
  );
}

Резюме ключевых возможностей

  • useFormState — централизованное управление значениями, валидацией и отправкой.
  • useField — связывает поле с формой и доступностью.
  • useFieldArray — поддержка динамических массивов полей.
  • Реактивные ошибки — автоматическое обновление и корректные ARIA-атрибуты.
  • Гибкость интеграции — любые кастомные компоненты можно связать с формой через стандартные хуки.

Эта архитектура позволяет создавать сложные формы с динамическими полями, полной поддержкой доступности и централизованным управлением состояния без необходимости вручную синхронизировать поля и их ошибки.