Обработка ошибок

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

Использование useFormField для состояния ошибок

Хук useFormField позволяет управлять состоянием поля формы, включая ошибки валидации. Он возвращает объект с основными атрибутами:

import {useFormField} from '@react-aria/form';

function TextInput({label, error}) {
  let {labelProps, inputProps, descriptionProps, errorMessageProps} = useFormField({
    label,
    error
  });

  return (
    <div>
      <label {...labelProps}>{label}</label>
      <input {...inputProps} />
      {error && <span {...errorMessageProps}>{error}</span>}
    </div>
  );
}

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

  • error — строка с сообщением об ошибке; если она есть, React Aria автоматически связывает её с полем через aria-describedby.
  • errorMessageProps включает необходимые ARIA-атрибуты для корректного чтения экранными читалками.

Обработка ошибок в асинхронных компонентах

В компонентах с асинхронной загрузкой данных ошибки часто связаны с сетевыми запросами. React Aria не занимается непосредственно обработкой промисов, но предоставляет подходы для связывания состояния ошибки с UI.

Пример с асинхронной валидацией:

import {useAsyncList} from '@react-stately/data';

function UserList() {
  let list = useAsyncList({
    async load({signal}) {
      try {
        let res = await fetch('/api/users', {signal});
        if (!res.ok) throw new Error('Ошибка загрузки пользователей');
        return {items: await res.json()};
      } catch (err) {
        return {items: [], error: err.message};
      }
    }
  });

  return (
    <div>
      {list.error ? <div role="alert">{list.error}</div> : null}
      {list.items.map(user => <div key={user.id}>{user.name}</div>)}
    </div>
  );
}
  • role="alert" обеспечивает моментальное оповещение пользователя о возникшей ошибке.
  • Важно использовать проверку list.error перед рендером элементов списка, чтобы избежать некорректного состояния UI.

Обработка ошибок в интерактивных компонентах

Для компонентов управления, таких как селекты и чекбоксы, React Aria предоставляет хуки useComboBox и useCheckboxGroup. Ошибки здесь часто связаны с неправильным состоянием или ограничениями ввода. Например:

import {useComboBox} from '@react-aria/combobox';
import {useState} from 'react';

function CountrySelect({countries}) {
  let [value, setValue] = useState('');
  let [error, setError] = useState('');

  let {inputProps, listBoxProps} = useComboBox({
    label: 'Выберите страну',
    items: countries,
    selectedKey: value,
    onSelectionChange: key => {
      if (!countries.includes(key)) setError('Неверная страна');
      else setError('');
      setValue(key);
    }
  });

  return (
    <div>
      <input {...inputProps} />
      {error && <span role="alert">{error}</span>}
    </div>
  );
}

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

  • Ошибки обрабатываются локально, но связываются с полем через role="alert".
  • Реактивное обновление состояния позволяет корректно отображать и скрывать сообщение об ошибке.

Интеграция с кастомными валидациями

React Aria допускает интеграцию с любыми схемами валидации, например с yup или zod. Главная задача — передавать результат валидации через error или напрямую в ARIA-атрибуты:

import * as yup from 'yup';
import {useFormField} from '@react-aria/form';

const schema = yup.object({
  email: yup.string().email('Некорректный email').required('Обязательное поле')
});

function EmailInput({value, onChange}) {
  let [error, setError] = useState('');
  let {inputProps, errorMessageProps} = useFormField({label: 'Email', error});

  const validate = async (val) => {
    try {
      await schema.validate({email: val});
      setError('');
    } catch (err) {
      setError(err.message);
    }
  };

  return (
    <div>
      <input
        {...inputProps}
        value={value}
        onCha nge={(e) => {
          onChange(e.target.value);
          validate(e.target.value);
        }}
      />
      {error && <span {...errorMessageProps}>{error}</span>}
    </div>
  );
}

Преимущества такого подхода:

  • Сообщения об ошибках полностью управляемы через хук useFormField.
  • Автоматическая интеграция с ARIA позволяет сохранить доступность формы.

Общие рекомендации

  • Использовать role="alert" для критических ошибок, которые нужно немедленно донести до пользователя.
  • Связывать сообщения об ошибках с полями через aria-describedby.
  • Для асинхронных компонентов предусматривать состояния загрузки, ошибки и пустого списка.
  • Интегрировать сторонние библиотеки валидации через хук useFormField или через локальное состояние с реактивным обновлением ошибки.
  • Избегать отображения ошибок в консоли или скрытых элементах — все ошибки должны быть доступны для всех пользователей, включая пользователей экранных читалок.

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