Skip to content

React, Performance Gotchas

Code Splitting

Code splitting can be the biggest impact on the codebase performance. It acts on the principle that loading less code will speed up your app.

For example that we're building a complex application that includes the d3 library for graphing data. You need to keep an eye on the code you are including in your bundle so that you don’t accidentally make it so large that your app takes a long time to load. If that's the case you may consider code splitting.

You can “lazy-load” just the things that are currently needed by the user. Which can dramatically improve the performance of your app. While the overall amount of code in your app is not reduced at all. You’ve avoided loading code that the user may never need, and reduced the amount of code needed during the initial load.

Also see import(), dynamic import

Eager loading (preloading)

It's annoying when 90% of the time the reason the users are using the app is so they can interact with our BigFoo. We don't want to have to make them wait first to load the app and then again to load the BigFoo.

It can be a better experience if we have BigFoo start loading as soon as the user hovers or focues the label. So if they hover or focus the <label>, we can trigger a dynamic import for the globe module.

Also see

React.useMemo

If no array is provided, a new value will be computed on every render.

React.memo

If a component renders the same result given the same props, we can wrap it in a call to React.memo for a performance boost in some cases by memoizing the result. This means that React will skip rendering the component, and reuse the last rendered result.

React.memo only checks for prop changes. If your function component wrapped in React.memo has a useState, useReducer or useContext Hook in its implementation, it will still rerender when state or context change.

By default it will only shallowly compare complex objects in the props object. If you want control over the comparison, you can also provide a custom comparison function as the second argument.

Two mains reasons to use React.memo and React.useCallback

1- Referential equality

  • Prevent re-renders, via dependencies lists
  • Prevent re-render via props

React is only calling that function when the value is needed. On top of that React also stores previous values given the inputs and will return the previous value given the same previous inputs. That's memoization at work.

Context

The way that context works is that whenever the provided value changes from one render to another, it triggers a re-render of all the consuming components (which will re-render whether or not they're memoized).

Note that it does not re-render all children rather it re-renders all consumers.

  • React.memo can be used to prevent not intendet value changes.
  • Colocating state can be useful if location of the context is high up the tree unneccesarly.
  • Seperating context logically into domain-specific context providers can be useful if different unneeded domains/logic is in one context. So instead of one huge context it can be multpile smaller contexts.
Profile picture

I have a passion for all things web.