react-day-picker
react-day-picker copied to clipboard
Too slow with higher numberOfMonths
Relevant Issue
#374
Description
When setting the numberOfMonths
to a higher value like 10, the performance when selecting dates is really slow, it takes a lot slower than using a lower value like 2.
To reproduce
Fork this CodeSandbox: https://codesandbox.io/s/sandpack-project-forked-pzx9no?file=/App.tsx.
Steps
- Try selecting dates and observe how slow the response time.
- May change the
numberOfMonths
to be 1 and compare how much different.
I tested it and is also slow on mobile devices, this bug will be fixed @gpbl ?
It seems the calls of useDayRender
https://github.com/gpbl/react-day-picker/blob/04640ddb1dce1dbf16a7c0160bd3875f63732cc0/packages/react-day-picker/src/components/Day/Day.tsx#L21
are behind the performance issue. From there, we could investigate why these lines are so slow:
https://github.com/gpbl/react-day-picker/blob/13908986a048284159c4cbf536e6ff62141e8b35/packages/react-day-picker/src/hooks/useDayRender/useDayRender.tsx#L52-L74
I also suspect we could reduce the calls of isMatch
https://github.com/gpbl/react-day-picker/blob/5b9f24b7abbcab507c73f619d2446a671505d680/packages/react-day-picker/src/contexts/Modifiers/utils/getActiveModifiers.ts#L18
So far I haven't made any actual progress tho... @jech33 @rachanee-tw could you see why it is that slow?
Any update on that performance issue ? This is something that keeps us from migrating to v8 :crying_cat_face: Thanks again for your work !
Still face the issue, any suggestion?
I've investigated where it goes slow and it is because functions and hooks that are called for each day cell. When rendering a whole year, there are lot of cells to render, thus the performance issue is more visible.
There are for sure workarounds for the existing components, but I'd rather spend the time on something that fixes the issue at the root.
At the moment, I'm playing with the idea where the date calculations would happen at root level (once, before rendering) and not at day level. This would give space for some better debugging (where it is actually slow?) and improvements.
Some other ideas?
I investigated and found the similar clue that hooks cause rerendering in multiple levels. I think splitting states to multiple hooks and useMemo may be able to help. But by my low level of understanding of the code base I might be wrong.
I investigated and found the similar clue that hooks cause rerendering in multiple levels. I think splitting states to multiple hooks and useMemo may be able to help. But by my low level of understanding of the code base I might be wrong.
I've been playing with useMemo
, no luck: I suspect some objects are being created at render time (e.g. with newObj = { ...oldObj }
, which may cause the slow down and my problem to memoize the calculations. (...calculation that happens for each day, so with memoization we could run into some memory issues)
I think that moving up these function calls (from the Day
component to the root), we could have more space for optimization. Then, passing down the state as props would avoid the calls for each day. This mean we can deprecate the hooks.
import { DayPickerProps } from 'DayPicker';
/** Represent the current state of DayPicker */
export interface DayPickerState {
initialProps: DayPickerProps;
modifiers: {
selected: Date[];
interactive: Date[];
focused: Date[];
disabled: Date[];
hidden: Date[];
outside: Date[];
today: [Date];
rangeStart: [Date];
rangeEnd: Date[];
};
customModifiers: {
[name: string]: Date[];
};
navigation: {
currentMonth: Date;
displayMonths: Date[];
nextMonth?: Date;
previousMonth?: Date;
};
}
Thanks @rachanee-tw for the help!