Using CalendarList, the date list is a bit slow to load
The code is as follows. I got the date data of the last ten years. I put the time selection in the pop-up window. It will be a little slow to load every time, as shown in the first picture. The second one is the picture after loading. How to solve this problem?
<CalendarList markingType="period" markedDates={markedDates} onDayPress={handleDayPress} minDate={minDate} maxDate={maxDate} pastScrollRange={120} futureScrollRange={0} scrollEnabled={true} calendarWidth={width} calendarHeight={300} hideDayNames={true} // ้่ๅ
็ฝฎ็ๆๆๅ็งฐ monthFormat={'yyyyๅนด MMๆ'} />
Same here.
+1
to add a loading mask on calendar view and set theme to hide the date when loading 'stylesheet.calendar-list.main': { placeholderText: { // text styles color: 'transparent', }, },
Same here, I don't know if there is a way of preloading it before using it?
I "solved" this by preloading the calendar component off-screen while the user is on a different tab/view.
The Fix:
// Preload CalendarList invisibly while on other view {shouldPreload && ( <View style={{ position: 'absolute', top: -2000, opacity: 0, pointerEvents: 'none' }}> <CalendarList {...calendarProps} /> </View> )}
When user switches to calendar view, the component is already rendered in memory - no more flash.
Delay the preload by ~1 second to avoid affecting initial load performance.
'stylesheet.calendar-list.main': { placeholderText: { // text styles color: 'transparent', }, },
What am I doing wrong since this doesn't help and the date string is still visible?
<CalendarList ref={calendarRef} pastScrollRange={6} futureScrollRange={0} firstDay={1} scrollEnabled showScrollIndicator markingType="period" markedDates={...} onDayPress={...} monthFormat="MMMM yyyy" style={...} theme={{ stylesheet: { 'calendar-list': { main: { placeholderText: { color: 'transparent', }, }, }, }, }} />
same problem here
Here is the solution to this:
const Calendar = () => {
const [startDate, setStartDate] = React.useState<string | null>(null);
const [endDate, setEndDate] = React.useState<string | null>(null);
const [isCalendarLoading, setIsCalendarLoading] = React.useState(true);
React.useEffect(() => {
const timer = setTimeout(() => {
setIsCalendarLoading(false);
}, 200); // 2 second loading
return () => clearTimeout(timer);
}, []);
const handleDayPress = (day: { dateString: string }) => {
const dateString = day.dateString;
// If no start date is selected, set it as start date
if (!startDate) {
setStartDate(dateString);
setEndDate(null);
return;
}
// If start date is selected but no end date
if (startDate && !endDate) {
// If the selected date is before start date, make it the new start date
if (new Date(dateString) < new Date(startDate)) {
setStartDate(dateString);
setEndDate(startDate);
} else {
// Set as end date
setEndDate(dateString);
}
return;
}
// If both dates are selected, reset and start over
setStartDate(dateString);
setEndDate(null);
};
const getMarkedDates = () => {
const marked: Record<
string,
{
startingDay?: boolean;
endingDay?: boolean;
color: string;
textColor: string;
}
> = {};
if (!startDate) return marked;
// Mark start date
marked[startDate] = {
startingDay: true,
color: "#FF6B35",
textColor: "#FFFFFF",
};
if (!endDate) return marked;
// Mark end date
marked[endDate] = {
endingDay: true,
color: "#FF6B35",
textColor: "#FFFFFF",
};
// Mark dates in between
const start = new Date(startDate);
const end = new Date(endDate);
const current = new Date(start);
while (current < end) {
current.setDate(current.getDate() + 1);
const dateString = current.toISOString().split("T")[0];
if (dateString !== endDate) {
marked[dateString] = {
color: "#FFE5D9",
textColor: "#FF6B35",
};
}
}
return marked;
};
const markedDates = getMarkedDates();
// Theme with transparent dates when loading
const calendarTheme = {
backgroundColor: "transparent",
calendarBackground: "transparent",
textSectionTitleColor: "#6B7280",
selectedDayBackgroundColor: "#FF6B35",
selectedDayTextColor: "#FFFFFF",
todayTextColor: "#FF6B35",
dayTextColor: "#374151",
textDisabledColor: "#D1D5DB",
dotColor: "#FF6B35",
selectedDotColor: "#FFFFFF",
arrowColor: "#FF6B35",
monthTextColor: "#111827",
indicatorColor: "#FF6B35",
textDayFontFamily: "System",
textMonthFontFamily: "System",
textDayHeaderFontFamily: "System",
textDayFontWeight: "400" as const,
textMonthFontWeight: "600" as const,
textDayHeaderFontWeight: "500" as const,
textDayFontSize: 16,
textMonthFontSize: 18,
textDayHeaderFontSize: 14,
...(isCalendarLoading && {
"stylesheet.calendar-list.main": {
placeholderText: {
color: "transparent",
},
},
}),
};
return (
<View style={styles.root}>
<View style={styles.calendarContainer}>
<CalendarList
onDayPress={handleDayPress}
onVisibleMonthsChange={(months) => {
console.log("now these months are visible", months);
}}
pastScrollRange={12}
futureScrollRange={12}
scrollEnabled={!isCalendarLoading}
showScrollIndicator={false}
markedDates={isCalendarLoading ? {} : markedDates}
calendarHeight={340}
calendarWidth={Dimensions.get("window").width - SAFE_AREA_VIEW_PADDING * 2}
removeClippedSubviews={true}
initialNumToRender={1}
maxToRenderPerBatch={1}
windowSize={5}
theme={calendarTheme}
markingType="period"
/>
{isCalendarLoading && <View style={styles.loadingMask}>{/* Calendar Skeleton */}</View>}
</View>
</View>
);
};
const styles = StyleSheet.create({
root: {
flex: 1,
backgroundColor: "#FFF",
},
calendarContainer: {
flex: 1,
paddingTop: 20,
paddingBottom: 20,
alignItems: "center",
justifyContent: "center",
position: "relative",
},
loadingMask: {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: "rgba(255, 255, 255, 0.9)",
justifyContent: "center",
alignItems: "center",
zIndex: 10,
},
});
export default Calendar;