useDateRangePicker — это хук из библиотеки React Aria,
предназначенный для создания полностью доступных интерфейсов выбора
диапазона дат. Он объединяет несколько сложных компонентов
пользовательского интерфейса:
Хук обеспечивает доступность (ARIA), поддержку клавиатуры, локализацию, а также взаимодействует с библиотекой React Stately, которая управляет состоянием компонента.
useDateRangePicker не рендерит UI напрямую. Он
предоставляет набор props, которые необходимо передать
в DOM-элементы.
Компонент выбора диапазона дат состоит из нескольких независимых частей.
Основные элементы интерфейса:
Типичная структура:
DateRangePicker
├─ Group
│ ├─ DateInput (start)
│ ├─ Separator
│ ├─ DateInput (end)
│ └─ Button
└─ Popover
└─ RangeCalendar
useDateRangePicker управляет связью между этими
частями.
Для работы необходимы несколько пакетов.
npm install @react-aria/datepicker
npm install @react-stately/datepicker
npm install @internationalized/date
Каждый пакет выполняет отдельную роль:
| Пакет | Назначение |
|---|---|
| React Aria | доступность и взаимодействия |
| React Stately | управление состоянием |
| internationalized/date | работа с датами и локалями |
Минимальный пример использования useDateRangePicker.
import {useDateRangePicker} from "@react-aria/datepicker";
import {useDateRangePickerState} from "@react-stately/datepicker";
import {useRef} from "react";
function DateRangePicker(props) {
let state = useDateRangePickerState(props);
let ref = useRef();
let {
groupProps,
startFieldProps,
endFieldProps,
buttonProps,
dialogProps,
calendarProps
} = useDateRangePicker(props, state, ref);
return (
<div {...groupProps} ref={ref}>
<DateField {...startFieldProps} />
<span>—</span>
<DateField {...endFieldProps} />
<button {...buttonProps}>?</button>
{state.isOpen &&
<Popover>
<Dialog {...dialogProps}>
<RangeCalendar {...calendarProps} />
</Dialog>
</Popover>
}
</div>
);
}
useDateRangePickerState)useDateRangePicker не управляет состоянием
самостоятельно. Оно создаётся через
useDateRangePickerState.
let state = useDateRangePickerState(props);
Состояние хранит:
Основные свойства состояния:
| Свойство | Назначение |
|---|---|
value |
текущий диапазон |
setValue() |
обновление диапазона |
isOpen |
открыт ли календарь |
open() |
открыть календарь |
close() |
закрыть календарь |
Значение диапазона представляется объектом:
{
start: CalendarDate,
end: CalendarDate
}
Пример:
{
start: new CalendarDate(2024, 4, 1),
end: new CalendarDate(2024, 4, 10)
}
CalendarDate — тип из
@internationalized/date, который не зависит от
часовых поясов.
useDateRangePicker возвращает набор props для различных
элементов.
groupPropsНазначается контейнеру компонента.
<div {...groupProps}>
Отвечает за:
startFieldPropsПередаётся в компонент поля начала диапазона.
<DateField {...startFieldProps} />
Обеспечивает:
endFieldPropsИспользуется для поля окончания диапазона.
<DateField {...endFieldProps} />
React Aria автоматически:
buttonPropsProps для кнопки открытия календаря.
<button {...buttonProps}>?</button>
Кнопка:
dialogPropsИспользуется для контейнера всплывающего окна.
<Dialog {...dialogProps}>
Отвечает за:
calendarPropsПередаётся в компонент календаря.
<RangeCalendar {...calendarProps} />
Этот компонент:
RangeCalendarКалендарь для диапазонов обычно создаётся с
useRangeCalendar.
Пример:
function RangeCalendar(props) {
let state = useRangeCalendarState(props);
let ref = useRef();
let {calendarProps} = useRangeCalendar(props, state, ref);
return (
<div {...calendarProps} ref={ref}>
{/* календарная сетка */}
</div>
);
}
React Aria поддерживает несколько типов ограничений.
<DateRangePicker
minValue={new CalendarDate(2024, 1, 1)}
/>
<DateRangePicker
maxValue={new CalendarDate(2024, 12, 31)}
/>
Можно контролировать диапазон вручную:
function isInvalid(range) {
if (!range) return false
let days = differenceInDays(range.start, range.end)
return days > 30
}
DateRangePicker может работать в controlled
режиме.
let [value, setValue] = useState(null)
<DateRangePicker
value={value}
onCha nge={setValue}
/>
Это позволяет:
React Aria автоматически использует локаль браузера.
Для явного указания:
<I18nProvider locale="ru-RU">
<DateRangePicker />
</I18nProvider>
Локализация влияет на:
DateField состоит из сегментов.
Пример формата:
ДД.ММ.ГГГГ
Каждый сегмент редактируется отдельно:
| Сегмент | Поведение |
|---|---|
| день | стрелки увеличивают значение |
| месяц | автопереход |
| год | ввод числа |
Навигация:
Popover открывается через состояние:
state.open()
state.close()
Обычно используется автоматически через buttonProps.
Пример:
{state.isOpen && (
<Popover>
<Dialog {...dialogProps}>
<RangeCalendar {...calendarProps} />
</Dialog>
</Popover>
)}
Компонент поддерживает полный набор взаимодействий.
| Клавиша | Действие |
|---|---|
| Tab | переход между полями |
| ← → | переключение сегментов |
| ↑ ↓ | изменение значения |
| цифры | ввод даты |
| Клавиша | Действие |
|---|---|
| стрелки | перемещение по дням |
| PageUp | предыдущий месяц |
| PageDown | следующий месяц |
| Enter | выбор даты |
| Esc | закрыть календарь |
Выбор происходит в два этапа.
Если конечная дата раньше начальной:
React Aria автоматически:
Можно отключать отдельные дни.
<DateRangePicker
isDateUnavailable={(date) =>
date.day === 1
}
/>
Такие даты:
Пример — запрет будущих дат.
<DateRangePicker
maxValue={today(getLocalTimeZone())}
/>
Запрет прошлых:
<DateRangePicker
minValue={today(getLocalTimeZone())}
/>
React Aria использует объекты:
CalendarDateZonedDateTimeCalendarDateTimeВыбор зависит от сценария.
| Тип | Когда использовать |
|---|---|
| CalendarDate | обычные даты |
| CalendarDateTime | дата + время |
| ZonedDateTime | с часовым поясом |
Для диапазонов чаще применяется CalendarDate.
React Aria не навязывает UI.
Можно создавать любой дизайн.
Пример:
[ 01.05.2024 ] — [ 10.05.2024 ] ?
или
Check-in Check-out
[ 01 May ] [ 10 May ]
DateRangePicker легко интегрируется с формами.
Пример с HTML form:
<form>
<DateRangePicker name="booking" />
</form>
Значение сериализуется автоматически.
Без useDateRangePickerState хук не работает.
Использование Date вместо CalendarDate
приводит к проблемам с таймзонами.
Важно сохранять структуру:
DateRangePicker
├─ DateField
├─ DateField
├─ Button
└─ RangeCalendar
React Aria оптимизирован для:
Состояние хранится централизованно, поэтому даже сложные компоненты остаются производительными.
useDateRangePicker можно комбинировать с другими хуками
React Aria:
usePopoveruseDialoguseButtonuseRangeCalendaruseDateFieldЭто позволяет строить сложные кастомные интерфейсы выбора диапазонов, полностью контролируя поведение и внешний вид.