react-day-picker icon indicating copy to clipboard operation
react-day-picker copied to clipboard

Too slow with higher numberOfMonths

Open rachanee-tw opened this issue 2 years ago • 7 comments

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

  1. Try selecting dates and observe how slow the response time.
  2. May change the numberOfMonths to be 1 and compare how much different.

rachanee-tw avatar Jun 22 '22 08:06 rachanee-tw

I tested it and is also slow on mobile devices, this bug will be fixed @gpbl ?

jech33 avatar Jul 11 '22 14:07 jech33

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?

gpbl avatar Oct 09 '22 17:10 gpbl

Any update on that performance issue ? This is something that keeps us from migrating to v8 :crying_cat_face: Thanks again for your work !

oudoulj avatar Nov 18 '22 08:11 oudoulj

Still face the issue, any suggestion?

rachanee-tw avatar Feb 09 '23 08:02 rachanee-tw

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?

gpbl avatar Feb 11 '23 14:02 gpbl

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.

rachanee-tw avatar Feb 14 '23 08:02 rachanee-tw

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!

gpbl avatar Feb 14 '23 11:02 gpbl