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.