React Performance & Optimization

Performance in React apps can be thought of in 2 ways:

  1. Loading Performance - Compressing & loading code/assets (mostly Non-React things)
  2. Runtime Performance - CPU & rendering issues (mostly React-specific things)

Loading vs. Runtime

Loading Performance - This is a measure of how fast the content is loaded when a user visits your webpage. Some specific metrics are First Contentful Paint (FCP), Largest Contentful Paint (LCP), First Input Delay (FID), TTI (Time to Interactive), and maybe a "Speed Index".

Runtime Performance - This is a measure of how "smooth" your application runs and functions after the initial load. Some specific metrics for this might be "frame rate", "CPU", and "Memory Usage".

Measuring Loadtimes

Optimizing Loadtimes

Send as little code/media as possible over the network, and optimize everything

  • Utilize GZip compression server-side to compress all in-flight HTTP requests
  • Optimize all images and videos included in the bundle
  • Building and Minifying all project assets to CSS / JavaScript
  • Various Methods of Code Splitting
  • Server-Side Rendering (SSR) and Static Site Generation (SSG) can improve the First Contentful Paint and Time to Interactive metrics, as they allow the browser to render the page more quickly (and are accessible by search engines).
    • Adding SSR / SSG to an existing project is no small feat and will take you more than an afternoon. Try to evaluate early on if your application would benefit from these technologies so you can configure your project the right way from the start.

Measuring Runtimes

Modern React is pretty fast by default. Unless you're building complex components/features - you don't need to reach for optimization tactics until you notice a component/feature behaving slowly. The best advice to follow:

  1. Don't optimize too soon
  2. Know what to measure

In modern React apps, most of the performance issues you'll run into can probably be simplified down to rendering problems (either too slow, or too much). The visual in the tweet below explains how rendering can cause cascading effects across a large application.

Other helpful resources for understanding how to measure runtime performance in React apps:

Optimizing Runtimes

Runtime performance issues usually boil down to two types of issues:

  1. Fixing Slow Renders

  2. Fixing Profuse Re-Renders

    • Use Refs for state & values that shouldn't cause re-renders (or that aren't rendered at all)
    • Be careful of setting state in an effect or outside of event-handlers / conditions

Memoization & Virtualization can solve slow renders or profuse re-renders in different ways:

UX Performance Best Practices

  • Consider throttling/debouncing frequent updates in the DOM. Humans can't see/process more than a few subtle updates in 1 second (1000 milliseconds), so there's no computational need to update something 100's of times per second.
    • Read more about how fast of an interaction is too fast for humans
    • For actual changes in the UI/data that's being shown, try not to show more than 4-5 updates per second. Any more, and the humans using your app won't even be able to tell the difference between each update, making it pointless.
    • RxJS has traditionally been a great resource for throttling data throughput in a JS application
    • Treat loading/pending states that are active for < 400ms uniquely, you should do either:
      • Simply don't show the loading state, as "delay" in the app that's < 400ms probably won't be perceivable by the users anyways
      • If you show the loading/pending state - require a minimum of ~400ms before switching back to a non-loading state

Typical Performance Hangups in React

Misc. Articles

More resources about optimizing JavaScript/React performance