В React Aria динамические коллекции представляют собой структуры данных, элементы которых могут изменяться во время работы приложения: добавляться, удаляться или модифицироваться. Работа с такими коллекциями требует корректной поддержки фокусировки, состояний выделения и доступности для вспомогательных технологий (screen readers, клавиатурная навигация и т.д.).
useListData для управления коллекциямиОсновным инструментом для работы с динамическими коллекциями в React
Aria является хук useListData. Он позволяет централизованно
управлять состоянием коллекции, отслеживать добавление и удаление
элементов, а также их сортировку и фильтрацию.
Пример базовой структуры:
import {useListData} from '@react-stately/data';
function Example() {
const list = useListData({
initialItems: [
{id: '1', name: 'Элемент 1'},
{id: '2', name: 'Элемент 2'}
]
});
return (
<div>
{list.items.map(item => (
<div key={item.id}>{item.name}</div>
))}
<button onCl ick={() => list.append({id: '3', name: 'Элемент 3'})}>
Добавить элемент
</button>
</div>
);
}
Ключевые моменты работы с
useListData:
append(item) — добавляет элемент в конец
коллекции.prepend(item) — добавляет элемент в начало.upd ate(id, newItem) — обновляет элемент с указанным
id.remove(id) — удаляет элемент по идентификатору.move(fromIndex, toIndex) — перемещает элемент внутри
коллекции.useListData автоматически генерирует уникальные
идентификаторы для элементов, если они не заданы, что важно для
корректной работы с ARIA-свойствами и предотвращения
конфликтов при динамических изменениях.
Для корректной доступности динамических коллекций необходимо сочетать
useListData с хуками React Aria, обеспечивающими
ARIA-поддержку, например:
useListBox — для визуализации и управления
списком.useOption — для отдельного элемента списка.Пример использования динамического списка с выделением:
import {useListBox, useOption} from '@react-aria/listbox';
import {useListData} from '@react-stately/data';
import {useSelectionState} from '@react-stately/selection';
function DynamicList() {
const list = useListData({
initialItems: [
{id: '1', name: 'Элемент 1'},
{id: '2', name: 'Элемент 2'}
]
});
const selection = useSelectionState({selectedKeys: new Se t()});
const {listBoxProps} = useListBox({selection}, list);
return (
<ul {...listBoxProps}>
{list.items.map(item => (
<Option key={item.id} item={item} selection={selection} />
))}
</ul>
);
}
function Option({item, selection}) {
const ref = React.useRef();
const {optionProps, isSelected, isFocused} = useOption(
{key: item.id},
selection,
ref
);
return (
<li {...optionProps} ref={ref} style={{background: isFocused ? 'lightblue' : 'transparent'}}>
{item.name} {isSelected && '(выбрано)'}
</li>
);
}
Особенности:
useOption автоматически управляет состоянием фокуса и
выделения для каждого элемента.selectionState хранит текущее состояние выделения и
синхронизируется с визуальными компонентами.Динамические коллекции часто загружаются с сервера. В этом случае
комбинация useListData с React state позволяет плавно
интегрировать асинхронные данные.
import {useEffect} from 'react';
import {useListData} from '@react-stately/data';
function AsyncList() {
const list = useListData({initialItems: []});
useEffect(() => {
fetch('/api/items')
.then(res => res.json())
.then(data => {
data.forEach(item => list.append(item));
});
}, []);
return (
<ul>
{list.items.map(item => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
}
Важные моменты:
id), чтобы
не ломалась фокусировка.useVirtualizer для оптимизации
рендеринга длинных списков.React Aria позволяет организовывать коллекции с группами элементов.
Для этого используются свойства children и
type: 'section' в useListData.
const list = useListData({
initialItems: [
{id: 'fruits', name: 'Фрукты', type: 'section', children: [
{id: 'apple', name: 'Яблоко'},
{id: 'banana', name: 'Банан'}
]},
{id: 'vegetables', name: 'Овощи', type: 'section', children: [
{id: 'carrot', name: 'Морковь'}
]}
]
});
Особенности работы с группами:
group и
listitem.useListData для централизованного
управления состоянием коллекции.useListBox, useOption) для автоматической
поддержки ARIA.useSelectionState и соответствующие
props.Эта архитектура обеспечивает создание динамических, доступных и производительных интерфейсов на React с полной интеграцией с ARIA.