I have custom created calendar using Flatlist. In the parent component I have a state with starting date and ending date and Press handler function to update state when user presses on the date. The problem is every time when I press the date render function invokes every time.
The question is: How to keep state to change, but not rerender whole calendar again and again?
Parent component with FlatList.
interface Props {
arrivalDate: string | undefined;
departureDate: string | undefined;
onDayPress: (day: Date) => void;
futureYearRange?: number;
}
const CustomCalendarList: React.FC<Props> = ({
arrivalDate,
departureDate,
futureYearRange = 5,
onDayPress,
}) => {
const months = useMonths();
const [isLoading, setIsLoading] = useState(true);
const [dates, setDates] = useState({
endDate: arrivalDate,
startDate: departureDate,
});
const handleDayPress= useCallback((row:IRow) => (e?: GestureResponderEvent) => {
if (!dates.startDate || (dates.startDate && dates.endDate)) {
setDates({endDate: undefined, startDate: row.date});
} else {
setDates(prevState => ({...prevState, endDate: row.date}))
}
}, [setDates]);
const { grids, monthsToRender } = useMemo(() => {
const monthToRender = 11 - dayjs().month() + futureYearRange;
const monthsToRender: Array<{ title: string; year: number }> = [];
const grids = [];
for (let i = 0; i < monthToRender; i++) {
const newGrid: Array<Array<IRow>> = [];
const date = dayjs().add(i, "month");
const daysInMonth = dayjs(date).daysInMonth();
const monthIndex = dayjs(date).month();
const year = dayjs(date).year();
monthsToRender.push({ title: months[monthIndex], year });
for (let j = 0; j < daysInMonth - 1; j++) {
let row = [];
// minus 1 because by default in dayjs start week day is sunday(index=0)
let startingIndex = j === 0 ? dayjs(date).startOf("month").day() - 1 : 0;
startingIndex = startingIndex === -1 ? 6 : startingIndex;
for (let k = startingIndex; k < 7; k++) {
if (!(j + 1 > daysInMonth)) {
row[k] = {
day: j + 1,
date: dayjs(date)
.date(j + 1)
.format("YYYY-MM-DD"),
};
}
if (k === 6) {
newGrid.push(row);
} else {
j += 1;
}
}
}
grids.push(newGrid);
};
console.log('generated')
return {
grids,
monthsToRender
};
}, [futureYearRange]);
const renderItem = useCallback(({
item,
index,
}: ListRenderItemInfo<Array<Array<IRow>>>) => {
return (
<Grid
onPress={handleDayPress}
monthsToRender={monthsToRender}
grid={item}
gridIndex={index}
/>
);
}, [dates.startDate, dates.endDate]);
useEffect(() => {
const timeoutId = setTimeout(() => {
setIsLoading(false);
}, 300);
return () => {
clearTimeout(timeoutId);
};
}, []);
if (isLoading) {
return (
<View
style={css`
height: 90%;
justify-content: center;
align-items: center;
background: ${colors.primaryBg};
`}
>
<ActivityIndicator color={"blue"} size="large" />
</View>
);
}
return (
<Calendar>
<FlatList
data={grids}
showsVerticalScrollIndicator={false}
updateCellsBatchingPeriod={1000}
renderItem={renderItem}
maxToRenderPerBatch={3}
keyExtractor={() => uuidv4()}
/>
</Calendar>
);
};