上下文

headless 包提供了包裹 hooks 并通过 React Context 暴露其状态的 Context provider。这启用了复合组件模式——将你的 UI 拆分成小的、专注的子组件,这些子组件从 context 中读取状态,而不是向下传递 props。

为何使用 Contexts?

如果不使用 context,你需要通过 props 传递每个状态片段:

// 不使用 context —— props 钻取
function MyDatePicker() {
const picker = useDatePicker({ value, onChange });
return (
<MyTrigger displayValue={picker.displayValue} onToggle={picker.handleToggle} />
<MyCalendar calendar={picker.calendar} getDayProps={picker.getDayProps} ... />
<MyFooter onConfirm={picker.handleConfirm} onCancel={picker.handleCancel} ... />
);
}

使用 context,子组件直接消费它们所需的内容:

// 使用 context —— 复合组件
function MyDatePicker() {
return (
<DatePickerProvider value={value} onChange={onChange}>
<ExampleWrapper variant="headless" client:visible>
<MyTrigger client:visible />
</ExampleWrapper>
<ExampleWrapper variant="headless" client:visible>
<MyCalendar client:visible />
</ExampleWrapper>
<ExampleWrapper variant="headless" client:visible>
<MyFooter client:visible />
</ExampleWrapper>
</DatePickerProvider>
);
}
function MyTrigger() {
const { displayValue, handleToggle } = useDatePickerContext();
return <button onClick={handleToggle}>{displayValue}</button>;
}

可用的 Provider

Provider内部使用的 Hook消费者 Hook
DatePickerProvideruseDatePickeruseDatePickerContext()
DateRangePickerProvideruseDateRangePickeruseDateRangePickerContext()
DateTimePickerProvideruseDateTimePickeruseDateTimePickerContext()
DateRangeTimePickerProvideruseDateRangeTimePickeruseDateRangeTimePickerContext()

每个 provider 都会渲染一个类型化 context(特定于该选择器类型)和一个统一的 PickerContext(在所有类型之间共享)。

import {
DatePickerProvider,
DateRangePickerProvider,
DateTimePickerProvider,
DateRangeTimePickerProvider,
} from "react-date-range-picker-headless";

DatePickerProvider

包裹 useDatePicker。提供 DatePickerContext + PickerContext

import type { DatePickerProviderProps } from "react-date-range-picker-headless";
属性类型描述
childrenReactNode**必需。**子组件。
valueDate | null**必需。**当前日期。
onChange(date: Date | null) => void**必需。**变更处理函数。
inlineboolean内联渲染(无弹出窗口)。
sizeDatePickerSize尺寸变体。
placeholderstring触发器占位符。
namestring表单字段名称。
…restBaseDatePickerOptions所有基本选项(minDate、maxDate、locale 等)。

消费者 hook:useDatePickerContext() 返回 UseDatePickerReturn

DateRangePickerProvider

包裹 useDateRangePicker。提供 DateRangePickerContext + PickerContext

import type { DateRangePickerProviderProps } from "react-date-range-picker-headless";
属性类型描述
childrenReactNode**必需。**子组件。
value{ start: Date | null; end: Date | null }**必需。**当前范围。
onChange(value: { start: Date | null; end: Date | null }) => void**必需。**变更处理函数。
inlineboolean内联渲染。
sizeDatePickerSize尺寸变体。
placeholderstring触发器占位符。
namestring表单字段名称。
maxDaysnumber范围内的最大天数。
minDaysnumber范围内的最小天数。
presetsDateRangePreset[]范围预设。
allowSingleDateInRangeboolean允许单日范围。
…restBaseDatePickerOptions所有基本选项。

消费者 hook:useDateRangePickerContext() 返回 UseDateRangePickerReturn

DateTimePickerProvider

包裹 useDateTimePicker。提供 DateTimePickerContext + PickerContext

import type { DateTimePickerProviderProps } from "react-date-range-picker-headless";
属性类型描述
childrenReactNode**必需。**子组件。
valueDate | null**必需。**当前日期时间。
onChange(dateTime: Date | null) => void**必需。**变更处理函数。
timeTimeConfig时间配置。
inlineboolean内联渲染。
sizeDatePickerSize尺寸变体。
placeholderstring触发器占位符。
namestring表单字段名称。
…restBaseDatePickerOptions所有基本选项。

消费者 hook:useDateTimePickerContext() 返回 UseDateTimePickerReturn

DateRangeTimePickerProvider

包裹 useDateRangeTimePicker。提供 DateRangeTimePickerContext + PickerContext

import type { DateRangeTimePickerProviderProps } from "react-date-range-picker-headless";
属性类型描述
childrenReactNode**必需。**子组件。
value{ start: Date | null; end: Date | null }**必需。**当前范围。
onChange(value: { start: Date | null; end: Date | null }) => void**必需。**变更处理函数。
timeTimeConfig时间配置。
inlineboolean内联渲染。
sizeDatePickerSize尺寸变体。
placeholderstring触发器占位符。
namestring表单字段名称。
maxDaysnumber范围内的最大天数。
minDaysnumber范围内的最小天数。
presetsDateRangePreset[]范围预设。
allowSingleDateInRangeboolean允许单日范围。
…restBaseDatePickerOptions所有基本选项。

消费者 hook:useDateRangeTimePickerContext() 返回 UseDateRangeTimePickerReturn

PickerContext (统一)

每个 provider 还注入一个统一的 PickerContext。这是一个超集 context,包含每种选择器类型的所有字段,并为特定于选择器的值提供可选字段。

import { usePickerContext } from "react-date-range-picker-headless";
function MyGenericHeader() {
const { locale, handlePrevMonth, handleNextMonth, calendars } = usePickerContext();
return (
<div>
<button onClick={handlePrevMonth}>{locale.prevMonth}</button>
<span>{locale.formatMonthYear(calendars[0].month)}</span>
<button onClick={handleNextMonth}>{locale.nextMonth}</button>
</div>
);
}

统一的 context 允许你构建可在所有选择器类型中工作的共享子组件。样式化包(styledtailwind3tailwind4)在内部使用此模式——它们的 HeaderGridFooter 等组件都消费 PickerContext

PickerContext 字段

import { PickerContext, usePickerContext } from "react-date-range-picker-headless";
import type { PickerContextValue } from "react-date-range-picker-headless";
function usePickerContext(): PickerContextValue;

如果在选择器 provider 之外使用,则会抛出错误。

核心字段 (始终存在)

字段类型
isOpenboolean
localeLocale
focusedDateDate | null
displayValuestring
hasValueboolean
canConfirmboolean
calendarsCalendarMonth[]
getDayProps(date: Date, referenceMonth?: Date) => DayProps
handleToggle() => void
handleOpen() => void
handleClose() => void
handleConfirm() => void
handleCancel() => void
handleClear() => void
handleGoToToday() => void
handlePrevMonth() => void
handleNextMonth() => void
handleKeyDown(e: KeyboardEvent<HTMLElement>) => void
handleDateClick(date: Date) => void
containerRefRefObject<HTMLDivElement | null>
popupRefRefObject<HTMLDivElement | null>
yearsnumber[]
monthsnumber[]
handleYearSelect(year: number, calendarIndex?: number) => void
handleMonthSelect(month: number, calendarIndex?: number) => void

UI 传递字段

字段类型
valueunknown
endNamestring | undefined
requiredboolean | undefined
inlineboolean | undefined
showOutsideDaysboolean | undefined
sizeDatePickerSize | undefined
placeholderstring | undefined
namestring | undefined
captionLayoutCaptionLayout | undefined

范围特定字段 (可选)

字段类型
handleDateHover((date: Date | null) => void) | undefined
presetsDateRangePreset[] | undefined
handlePresetClick((preset: DateRangePreset) => void) | undefined
activePresetIndexnumber | undefined

单一时间字段 (可选, DateTimePicker)

字段类型
resolvedTimeConfigRequired<TimeConfig> | undefined
tempHournumber | undefined
tempMinutenumber | undefined
tempSecondnumber | undefined
tempPeriodTimePeriod | undefined
handleHourChange((hour: number) => void) | undefined
handleMinuteChange((minute: number) => void) | undefined
handleSecondChange((second: number) => void) | undefined
handlePeriodChange((period: TimePeriod) => void) | undefined
isTimePickerOpenboolean | undefined
handleTimePickerOpen(() => void) | undefined
handleTimePickerClose(() => void) | undefined
handleTimePickerConfirm(() => void) | undefined
handleTimePickerCancel(() => void) | undefined
timePickerRefRefObject<HTMLDivElement | null> | undefined
timeDisplayValuestring | undefined

范围时间字段 (可选, DateRangeTimePicker)

字段类型
startHournumber | undefined
startMinutenumber | undefined
startSecondnumber | undefined
startPeriodTimePeriod | undefined
endHournumber | undefined
endMinutenumber | undefined
endSecondnumber | undefined
endPeriodTimePeriod | undefined
handleStartHourChange((hour: number) => void) | undefined
handleStartMinuteChange((minute: number) => void) | undefined
handleStartSecondChange((second: number) => void) | undefined
handleStartPeriodChange((period: TimePeriod) => void) | undefined
handleEndHourChange((hour: number) => void) | undefined
handleEndMinuteChange((minute: number) => void) | undefined
handleEndSecondChange((second: number) => void) | undefined
handleEndPeriodChange((period: TimePeriod) => void) | undefined
isStartTimePickerOpenboolean | undefined
isEndTimePickerOpenboolean | undefined
handleStartTimePickerOpen(() => void) | undefined
handleStartTimePickerClose(() => void) | undefined
handleStartTimePickerConfirm(() => void) | undefined
handleStartTimePickerCancel(() => void) | undefined
handleEndTimePickerOpen(() => void) | undefined
handleEndTimePickerClose(() => void) | undefined
handleEndTimePickerConfirm(() => void) | undefined
handleEndTimePickerCancel(() => void) | undefined
startTimePickerRefRefObject<HTMLDivElement | null> | undefined
endTimePickerRefRefObject<HTMLDivElement | null> | undefined
startTimeDisplayValuestring | undefined
endTimeDisplayValuestring | undefined

类型化 vs 统一 Contexts