Flatpickr изначально проектировался как DOM-ориентированная библиотека, а не как реактивный фреймворк. Это означает, что внутреннее состояние календаря существует отдельно от состояния приложения, а синхронизация осуществляется через явные события и API-вызовы.
Реактивность в контексте Flatpickr — это не встроенная система отслеживания изменений, а набор механизмов:
Ключевая идея заключается в том, что календарь не «знает» о состоянии приложения, но может быть приведён в соответствие с ним.
Двусторонняя привязка в контексте Flatpickr означает синхронизацию двух источников состояния:
Синхронизация должна работать в обе стороны:
При этом важно учитывать отсутствие автоматической реактивности — каждое обновление требует явного вызова API.
Основной механизм получения данных из Flatpickr — событие
onChange:
const fp = flatpickr("#date", {
onChange: (selectedDates, dateStr, instance) => {
appState.date = dateStr;
}
});
Здесь:
selectedDates — массив объектов DatedateStr — форматированная строкаinstance — экземпляр календаряЭтот механизм обеспечивает поток данных из UI в состояние приложения.
Для обратной синхронизации используется метод
setDate:
fp.setDate(appState.date, true);
Параметры:
triggerChange управляет вызовом
событийКлючевой момент: при triggerChange = true возможно
возникновение циклических обновлений, если не контролировать поток
данных.
При реализации двусторонней привязки возникает риск бесконечного цикла:
onChangeappStatesetDateonChangeТиповой способ решения — сравнение значений перед установкой:
function syncDate(newDate) {
const current = fp.input.value;
if (current !== newDate) {
fp.setDate(newDate, false);
}
}
Дополнительно используется флаг блокировки:
let internalUpdate = false;
const fp = flatpickr("#date", {
onChange: (dates, str) => {
if (internalUpdate) return;
appState.date = str;
}
});
function updateFromState(value) {
internalUpdate = true;
fp.setDate(value, false);
internalUpdate = false;
}
При интеграции Flatpickr обычно используются два подхода:
Состояние хранит dateStr:
Состояние хранит Date или массив Date:
В чистом JavaScript реактивность реализуется вручную через наблюдатели состояния:
const state = {
_date: null,
set date(value) {
this._date = value;
syncCalendar(value);
},
get date() {
return this._date;
}
};
function syncCalendar(value) {
if (!fp) return;
fp.setDate(value, false);
}
Такая модель позволяет централизовать поток данных.
В React Flatpickr обычно используется как controlled component:
const [date, setDate] = useState("");
useEffect(() => {
if (fpRef.current) {
fpRef.current.setDate(date, false);
}
}, [date]);
return (
<input
ref={el => {
if (!el) return;
fpRef.current = flatpickr(el, {
onChange: (_, str) => setDate(str)
});
}}
/>
);
Особенность:
Во Vue интеграция строится вокруг реактивных ref и
watch:
const date = ref("");
onMounted(() => {
const fp = flatpickr(input.value, {
onChange: (_, str) => {
date.value = str;
}
});
watch(date, (val) => {
fp.setDate(val, false);
});
});
Особое внимание требуется уделять предотвращению лишних обновлений при инициализации.
В Angular Flatpickr интегрируется через форму:
writeValue(value: string): void {
this.fp.setDate(value, false);
}
registerOnChange(fn: any): void {
this.onCha nge = fn;
}
ngAfterViewInit() {
this.fp = flatpickr(this.el.nativeElement, {
onChange: (_, str) => this.onChange(str)
});
}
Система Angular формализует двустороннюю привязку через интерфейсы, а Flatpickr выступает внешним источником событий.
В Svelte реактивность встроена в язык:
let date = "";
onMount(() => {
const fp = flatpickr(input, {
onChange: (_, str) => {
date = str;
}
});
$: fp && fp.setDate(date, false);
});
Здесь реактивная декларация $: обеспечивает
автоматическую синхронизацию.
Одной из ключевых проблем при двусторонней привязке в Flatpickr является формат строки:
dateFormatНесоответствие форматов приводит к ложным изменениями состояния и лишним перерендерингам.
Решение:
formatDate и parseDate
APIОсновные методы синхронизации:
setDate(date, triggerChange)clear()jumpToDate(date)changeMonth(step)Комбинация этих методов позволяет реализовать внешнюю реактивность без встроенного state manager.
В типичной интеграции Flatpickr существует два направления потоков:
Отсутствие автоматического связывания требует строгого контроля:
setDate внутри onChange без
проверкиdestroy()При реактивных обновлениях важно учитывать пересоздание:
useEffect(() => {
const fp = flatpickr(input.current, config);
return () => fp.destroy();
}, []);
Это предотвращает утечки и конфликт состояний при повторной инициализации.
Реактивная интеграция Flatpickr сводится к следующей схеме: