Performance optimisations for React applications: Round 2
Normalised state and connected components
*Be sure to read Performance optimisations for React applications first!
I recently gave a talk at React Sydney in which I put forward some ideas and techniques to significantly increase the performance of your React applications (again). In the talk I address some of the style and performance pain points in the techniques I put forward in my original post. Following the updated recommendations can result in extremely significant performance improvements as well as increased loose coupling between components.
I would suggest watching the talk first. To save you needing to take notes I have summarised some of the key findings for your future reference.
Use Normalised state
Normalised state (think database tables) is much more sane to work with than denormalised state (where everything merged together). Denormalised state can be hard to preserve across server updates as there is no clear distinction between temporary user interface state and persisted entity state.
Use lots of connected (smart) components
Connect as many components as makes sense in your application to your data store rather than relying on one store connection at the root. Connected components individually query the store on state changes to get the state that they care about. This technique facilitates the use of normalised state as well as allowing components to know as little as possible about their children and avoids needing to pass redundant props.
Write efficient state queries
Querying data in the store from your connected components can be expensive (lots of unneeded data transformation) and can cause redundant rendering if the the result of the query has not changed but causes a render anyway. Get comfortable and familiar with memoization (caching function calls) as it will help solve this problem. If you are using react-redux be sure to check out reselect to help create efficient state queries (selectors). As an aside, I wrote memoizeOne which comes in handy as well. It is also worth looking into breaking queries into multiple queries that invalidate in parts. This will allow you to bust memoization caches as little as possible.
Some tips for writing efficient state queries:
- Aggressively lean on patterns and shapes that allow you to leverage memoization
- Make sure you invalidate references only if state that is changing
- Break queries into multiple queries that invalidate in parts. This will allow you to bust memoization caches as little as possible.
- If your state queries rely on your own props, be sure to have a unique memoization function for each component (more on this topic).
Thanks for watching and reading and all the best in making highly performant React apps!