Harrison Grieve
Harrison Grieve

Reputation: 161

How can I most easily identify bottlenecks in React render performance?

I'm having an issue with identifying bottlenecks in render performance while working on a JSON viewer. With few elements, it performs well, but at a certain point it becomes annoyingly slow.

Checking the profiler, it seems that elements are rendering fast enough, but I've noticed a few issues that I'm not sure how to pursue.

Overview

Implementation

Issues

There are two functionalities which reproduce a slow response time with (not so big) JSON documents:

With the current implementation, both filtering and expanding all triggers a display: none change on the child elements, and the behavior leads me to believe I'm doing something inefficiently to handle this use case.

Reproduction Steps

The code is available here: https://codesandbox.io/s/react-json-view-4z348

With a production build here (not performing any better): https://csb-4z348.vercel.app/

To reproduce the issue, play around with the Expand All function (plus sign next to filter input) and some filter inputs.

Then, try loading a JSON feed with more elements (you can test on my GitHub API feed) and try filtering/expanding all. Notice the major performance hit.

What I've noticed

Question

While I would appreciate a nudge in the right direction for this specific case, what I'm most curious about is how best to identify what is causing these performance issues.

I've looked into windowing the output, but it's not my first choice, and I'm pretty sure I'm doing something wrong, rather than the cause being too many elements rendered.

I appreciate your time, and thank you in advance for any tips you could provide!

Upvotes: 6

Views: 1640

Answers (1)

Harrison Grieve
Harrison Grieve

Reputation: 161

It seems I've answered my own question. The problem was a reconciliation issue due to using UUID as a key prop in my child components, which caused them to re-render every time the minimize state changed. From the docs:

Keys should be stable, predictable, and unique. Unstable keys (like those produced by Math.random()) will cause many component instances and DOM nodes to be unnecessarily recreated, which can cause performance degradation and lost state in child components.

I'll leave the steps here for anyone else who runs into this issue.


After (too long) digging around in performance profiler, I noticed that each time I minimized or expanded the elements, each child was being mounted again. After consulting Google with a more specific query, I found this blog post and realized that I was committing this flagrant performance error.

Once I found the source of the problem, I found many other references to it.

After fixing the key prop, interaction time got ~60% faster for minimize/expand all.

Finally, I memoized some other components related to the instant filter and finally it seems to be performing as well as I would like for the time being.

Thanks to anyone who took a look at this in the meantime, and I hope it's helpful for anyone who might come across this.

Upvotes: 4

Related Questions