Troubleshooting
The following are the most common issues found when using Flash Calendar and a guide on how to fix them.
FlashList's rendered size is not usable.
Check out Flash List docs for instructions on how to fix this warning.
TLDR: ensure the parent of <Calendar.List />
has a fixed height or a
flex: 1
style.
ReferenceError: Can't find variable: Intl
(Android)
Flash Calendar uses Intl
primitives to format dates in a locale-aware way.
JavaScriptCore (jsc
), the legacy React Native JS runtime, doesn't support
Intl
out of the box on Android.
It's highly advised to upgrade to Hermes
, the new default JS runtime (more on
that). Besides better performance, it also
supports the Intl
primitives Flash Calendar uses. For Expo, update your
app.json
to use hermes
:
{
"expo": {
"jsEngine": "hermes"
}
}
If your company is stuck with jsc
, you can either use a polyfill, or bypass
Intl
entirely by providing your own date formatting
functions.
Calendar.List is slow when using date ranges
If you're seeing frame drops when using Calendar.List
, there's a high chance
you're suffering from too many re-renders. If you're not careful with
memoization, the entire list re-renders whenever the calendarActiveDateRanges
prop changes. Notice the frame drops and how each BaseCalendar
re-renders in
the React DevTools profiler (this is bad 👎):
import { Calendar, toDateId } from "@marceloterreiro/flash-calendar";
import { addMonths } from "date-fns";
import { Text } from "react-native";
const todayId = toDateId(new Date());
const maxDateId = toDateId(addMonths(new Date(), 12));
export const SlowExample = () => {
const [dateIds, setDateIds] = useState<string[]>([]);
const dateRanges = dateIds.map((dateId) => ({
startId: dateId,
endId: dateId,
}));
return (
<Calendar.VStack alignItems="stretch" grow spacing={12}>
<Text>⚠️ Don't copy-paste this example, it has performance issues</Text>
<Calendar.List
calendarActiveDateRanges={dateRanges}
calendarInitialMonthId={todayId}
calendarMaxDateId={maxDateId}
calendarMinDateId={todayId}
onCalendarDayPress={(dateId) => {
if (dateIds.includes(dateId)) {
setDateIds(dateIds.filter((id) => id !== dateId));
} else {
setDateIds([...dateIds, dateId]);
}
}}
/>
</Calendar.VStack>
);
};
The easiest fix is to use the provided useDateRange
hook. The hook is optimized by default
and works perfectly with Calendar.List
.
However, there might be cases where you need to control the onCalendarDayPress
event and decide how the date range logic works. In those cases, make sure you
memoize the onCalendarDayPress
and use the updater function
pattern.
Notice it runs on 60 FPS and the BaseCalendar
components don't re-render
anymore (this is good 👍):
import type { CalendarOnDayPress } from "@marceloterreiro/flash-calendar";
import { Calendar, toDateId } from "@marceloterreiro/flash-calendar";
import { addMonths } from "date-fns";
import { useCallback, useState } from "react";
import { Text } from "react-native";
const todayId = toDateId(new Date());
const maxDateId = toDateId(addMonths(new Date(), 12));
export const SlowExampleAddressed = () => {
const [dateIds, setDateIds] = useState<string[]>([]);
const dateRanges = dateIds.map((dateId) => ({
startId: dateId,
endId: dateId,
}));
// This is the fix: memoized onCalendarDayPress and updater function pattern
// It keeps `BaseCalendar` props stable, allowing each month to skip re-renders
const handleCalendarDayPress = useCallback<CalendarOnDayPress>((dateId) => {
setDateIds((dateIds) => {
if (dateIds.includes(dateId)) {
return dateIds.filter((id) => id !== dateId);
} else {
return [...dateIds, dateId];
}
});
}, []);
return (
<Calendar.VStack alignItems="stretch" grow spacing={12}>
<Text>✅ This is safe to copy, perf issues addressed</Text>
<Calendar.List
calendarActiveDateRanges={dateRanges}
calendarInitialMonthId={todayId}
calendarMaxDateId={maxDateId}
calendarMinDateId={todayId}
onCalendarDayPress={handleCalendarDayPress}
/>
</Calendar.VStack>
);
};