I am working on date picker component from
baseweb in past few days. I found out some serious performance issues. In this blog post I am
going to write about the process of finding performance problems in app. This is not specific to react as it only
uses the devtools that browser offers. If you are familiar with baseweb and directly want to look at the PR then visit
https://github.com/uber/baseweb/pull/4016. These changes are published in
v9.107.0
, so if you want to see how it was earlier then select the version < = 9.106.0 or click
https://v9-106-0.baseweb.design/
Before starting you can play with the datepicker component in baseweb documentation. Here is the image of time it took to re-render when we hover over one date and then other. This is the initial behavior, I will discuss two step process which reduced the re-render time by more than 50%.
In the above image, I tried to dig deeper and analysed each function and time it consumes. You can do the same by
clicking on Bottom-Up
tab in Performance dev tool. It shows the time taken by different activities with the file name.
First column Self Time represents the aggregated time spent directly in that activity, across all of its
occurrences. Second column Total Time represents the aggregated time spent directly in that activity, across all
of its occurrences. Clicking on the file name will take you to the function. This way you can locate the bottleneck in
your application. I am able to find out the first issue by going through activities in descending order of their total
time.
objectSpread
is spread operator. Problem is styles for each date is calculated every time we hover over any date.
There are 15 occurrences of spread operator in this file. It is always better to avoid premature optimization and aim
to write clean, readable code. But in this case we found out that spread is actually causing the performance issue
so we can replace spread with the native Object.assign
method. And it helped. This change reduced re-render time from
165ms to 145ms 🎉
Now repeat the cycle mentioned above. Go through all the functions mentioned in Bottom-Up
tab, and try to reduce the
unnecessary calculations if any. In this case I found out that list of month year
to show in drop down present in
calendar header is calculated every time we hover over date. Calculation is loop over MIN_YEAR
to MAX_YEAR
, then for
each year again loop over 12 months and create entries like January 2019
, February 2019
, ... Default MIN_YEAR
is
set to 2000 and MAX_YEAR
is 2030, that is 31*12=372 calculations every time even when it is not required to do so.
This is consuming around 40ms 😳. I memoized this calculation on MIN_YEAR
and MAX_YEAR
i.e. this calculations will
be made again only if either of these value changes.
This is big improvement from the point we started 🎊🎊. These are all the comparison in development mode. Here I would also like to present what we gain in production. This is the comparison when we are just hovering over the date randomly.
Before -
After -
These changes helped me to get rid of majority of frame drop and lag that we are experiencing while selecting the date.
If you are experiencing performance issues in your application, this may help you to identify the potential issues. If you are using react, then react developer tools made it very easy to find the root cause. You can record the activity, see the different commits and if some component is rerendering then it also shows the prop or state change that caused it.