How to reduce renders using redux + normalizr
Asked Answered
T

2

10

I have an app using React + Redux + Normalizr, I would like to know the best practices to reduce the number of renders when something changes on entities.

Right if I change just one entity inside the entities, it will re-render all the components and not only the components that need that specific entity

Toland answered 3/4, 2016 at 22:6 Comment(4)
Normally, React Shadow DOM only updates what truly changed, even though all render() methods are called in order to compute it. It should stay pretty fast. Do you have any profiled performances issues?Libbielibbna
Anyways, you can take a look a the shouldComponentUpdate lifecycle method to reduce the number of render computations.Libbielibbna
reselect will help you in some situation.Baresark
this comment explain a little bit better - github.com/reactjs/redux/issues/991#issuecomment-205895654Toland
P
15

There are several things you can do to minimize the number of renders in your app, and make updates faster. Let's look at them from your Redux store down to your React components.

  • In your Redux store, you can use immutable data structures (for example, Immutable.js). This will make all subsequent optimizations faster, as you'll be able to compare changes by only checking for previous/next state slice equality rather than recursively comparing all props.

  • In your containers, that is in your top-level components where you inject redux state as props, ask only for the state slices you need, and use the pure option (I assume you're using react-redux) to make sure your container will be re-rendered only if the state slices returned by your mapStateToProps functions have changed.

  • If you need to compute derived data, that is if you inject in your containers data computed from various state slices, use a memoized function to make sure the computation is not triggered again if the input doesn't change, and to keep object equality with the value the previous call returned. Reselect is a very good library to do that.

  • In your dumb components use the shouldComponentUpdate lifecycle to avoid a re-render when incoming props do not change. If you do not want to implement this manually, you can use React's PureRenderMixin to check all props for you, or, for example, the pure function from the Recompose library if you need more control. A good use case at this level is rendering a list of items. If your item component implements shouldComponentUpdate only the modified items will be re-rendered. But this shouldn't be a fix-all-problems habit : a good components separation is often preferable in that it makes flow props only to those components which will need them.

As far as Normalizr is concerned, there is nothing more specific to be done.

Phylactery answered 7/4, 2016 at 15:20 Comment(6)
To help you decide where to optimize, Dan Abramov just said on Twitter (twitter.com/dan_abramov/status/719723513016426496): "component separation can make a much bigger difference than manual shouldComponentUpdate() everywhere", because "connect() from React Redux already takes care of shouldComponentUpdate() for most cases. Focus on finding the optimal component separation".Danyelledanyette
@Danyelledanyette many thanks for the heads-up! I've edited the answer to include that remarkPhylactery
Regarding first item. Can you provide an example of immutable + redux store?Plastered
@Plastered well let's say you have a people reducer with the following structure : {1: {name: 'John', status: 'admin'}, {2: {name: 'Jack', status: 'user'}}, you could make it an immutable map of immutable maps. Updating one person like so : return state.setIn([1, 'status'], 'user') would return a new object for people, a new object for people.get(1) but the same object as before for people.get(2)Phylactery
@Phylactery thank you. Very helpful. We have this logic (map logic) running in the connect. It doesn't seems to work as expected. I'm somewhat concerned to use this in the redux store, since is not a state its actually derived data.Plastered
@Phylactery .. but I'll run some tests with your redux+immutable ideaPlastered
D
1

If in some case (it should be rare) you detect performance problems that are directly related to React's rendering cycles of components, then you should implement the shouldComponentUpdate() method in the involved components (details can be found in React's docs here).

Change-detection in shouldComponentUpdate() will be particularly easy because Redux forces you to implement immutable state:

shouldComponentUpdate(nextProps, nextState) {

    return nextProps.dataObject !== this.props.dataObject;

    // true when dataObject has become a new object,
    // which happens if (and only if) its data has changed,
    // thanks to immutability
}
Danyelledanyette answered 6/4, 2016 at 9:18 Comment(2)
could you address this comment - github.com/reactjs/redux/issues/991#issuecomment-205895654?Toland
At least for me this solely works if you're using trivial data. When you use derived data (for example form reselect) the inequality above will not work as expectedPlastered

© 2022 - 2024 — McMap. All rights reserved.