PolyWolf's Blog

Some Reasons Your React App Might Be Slow

Published: 5/1/2024, 9:29:01 PM

Originally published on Cohost in 2 parts.


Dan Luu, on Mastodon:

Naive question: why do React apps in the real world tend to be slow?

I tried doing a React tutorial and the result was quite fast (w.r.t. latency & CPU utilization on low-end devices) until the tutorial has you replace “manual” / “low-level” react calls with commonly used libraries, e.g., using TanStack Query instead of useEffect plus a manually instantiated cache.

Is the main issue that libraries tend to be big and slow or is there another major cause of React app slowness?

wow, a question i actually have a smidgen of expertise on!

At work, we have a very big React app. Here are some things which were causing slowness, which we know for certain because fixing them improved performance:

  1. Excessive use of react-redux and redux-saga. These are libraries which have you put everything you want to share between unrelated (not direct children) components in global state, and then runs “selectors” (arbitrary javascript functions to get specific data out of the global state) every time any of that state changes. Across thousands of selectors and many state changes per second, this really adds up. We have good reason to believe we’re one of the largest users of Redux, so this might not be an issue for everyone.
  2. Excessive rerenders, and non-memoized rerenders. You can have excessive rerenders when your component gets non-memoized objects (or, functions, arrays, etc.) as props. A child can do all the proper useCallback and useMemo it wants, but it’s on the parent to not mess up. Which happens often since it’s a pain to wrap every single arrow function in useCallback everywhere (React docs explicitly say to not do this until performance is a concern, even!). And even then, if a parent rerenders for whatever reason, it will rerender all its children, even if their props are all the same, unless the child is memoized, which is its own problem if the heirarchy is very deep.
  3. Too Many DOM nodes. This is a general problem with component-like frameworks, encouraging a kind of abstraction leading to far too many wrapper divs since they’re so easy to add. All these extra DOM nodes come at a surprising performance penalty, especially in browsers like Safari.

Not quite an exhaustive “things that make your React app slow”, but hopefully useful nonetheless :P


Other Reasons Your Very Big Website Might Be Very Slow:

  1. Animations. The designer loves to go ham and make absolutely everything animated, but eventually yeah those start to add up too, especially when animating massive DOM trees and causing big layout shifts. Combined with (3) above, it sometimes takes a solid 2 seconds to open a certain problematic side panel, on a good machine. Good luck on a little dinky machine. This problem is also exacerbated by using libraries like framer-motion, which have lots of cool animation curves, not all of them implemented efficiently! Using CSS animations where possible also lets you quickly turn them off with animation: none !important; transition: none !important;
  2. Opacity. The designer also loves using rgba(255, 255, 255, 0.05) for component backgrounds, because it layers nicely over almost any other background. Unfortunately, they require more work by the browser to render properly, which can amount to a surprising drop in performance on weaker clients. Especially when combined with animated transparencies🙀 Making an option to change to all flat colors was a noticeable gain. And this is all to say nothing of blur, which tanks performance even harder (we’ve almost got rid of it entirely now)
  3. Excessive Repaints From Weird Layouts. Still haven’t quite gotten to the bottom of this so can’t say for sure, but it seems that certain layout things (CSS grid? Weird stacking contexts?) cause browsers to think they need to repaint more than what’s actually changed, leading to a drop in performance. Saying “hey change the size of this one thing slightly” makes it go “oh i should repaint the whole screen, got it”, even when there’s no actual layout shift. This is once again exacerbated by animations, which cause this many times a second.

Once again, these are just problems we’ve identified, and there may be more, I am by no means a Web Performance Expert. yet.

#programming#reactjs#javascript