DEV Community

Alex Sidorenko
Alex Sidorenko

Posted on • Originally published at alexsidorenko.com

How to Detect Slow Renders in React?

Improving React app performance often comes down to finding bottlenecks and fixing them. One well-placed memoization can make a slow app fast again. But how to find performance bottlenecks?


Profile the problem

Open Rect Developer Tools Profiler tab. Click the record button to start profiling. Interact with the part of your app that feels slow, then click the record button again to stop profiling.

profile


Analyze the results

Find a slow commit you want to improve. You can see the commits bar in the right top corner of profiling results. For more info on commits, check out React Docs - Browsing Commits.

commits

In our case, 1st, 2nd, and 4th commits are slow. They take more than 300ms to render. Every response to a user action that takes more than 100ms breaks the connection between the action and the result (RAIL: A User-Centric Model For Performance).

Now let's pick one of these commits and check the "Flamegraph" to see what is causing this poor performance.

flamegraph

The Flamegraph shows our components tree. We can see that component Home and its entire sub-tree re-renders. The SearchResults component responsible for the main UI change is pretty fast and takes only 7.4ms to render. The SlowComponent takes most of the rendering time. It is the bottleneck.


Fix the bottleneck

Let's look into the code of a SlowComponent:

const SlowComponent = () => {

  // Expensive calculation that takes 300+ms
  const n = [...Array(3000000).keys()].reduce((p,c) => p + c)

  return (
    <p>Expensive calculation - {n}</p>
  )
}
Enter fullscreen mode Exit fullscreen mode

We can wrap our expensive calculation with useMemo to make sure it only runs when necessary. And since we don't rely on any of the props, we can leave the dependency array empty. This way, our expensive calculation will not be re-triggered every time SlowComponent re-renders.

const SlowComponent = () => {

  const n = useMemo(() => {
    // Expensive calculation that takes 300+ms
    return [...Array(3000000).keys()].reduce((p,c) => p + c)
  }, [])

  return (
    <p>Expensive calculation - {n}</p>
  )
}
Enter fullscreen mode Exit fullscreen mode

Now let's analyze performance again.

profile-2

The UI feels faster already. Let's check the commits.

commits-2

The 1st, 2nd, and 4th commits are still the slowest. But they each take around 12-17ms to render, which is 14 times faster than before. Let's analyze the Flamegraph to see what happened.

flamegraph-2

The SearchResults component takes the most time to render now. But since it's only 12ms, we have nothing to worry about. And now that we put our memoization in place, the SlowComponent takes only 0.3ms to render.


Originally published at alexsidorenko.com

Top comments (0)