Max Vorozhcov
Max Vorozhcov

Reputation: 602

React redux connect rendering optimisation

I am trying to get how to manage complex state in React, with limiting the number of render calls for components whose content has not changed.

As example:

I have simple connected to redux store container component with "items" props (which is array).

const Component = ({ items }) => (
    <>{items.map(item => <ItemComponent key={item.id} {...item} />}</>
);

const mapStateToProps = state => ({
    items: $$data.select.items(state),
});

const ConnectedComponent = connect(mapStateToProps)(MyComponent);

Every time any part of the complex store changes – the items prop changes also, even if items data didn't update, even if it is empty: oldProp: [] => newProp: []. And it causes rerendering. (I found it in React Dev Tools, it highlights updated components)

Should I worry about this unnecessary rerenders? What is the best way to deal with it? I already found that new React.memo hoc stops rerenderings, but is it good way ?

Upvotes: 4

Views: 1860

Answers (5)

lux
lux

Reputation: 8436

If you're using react-redux >= 6.0.0, there is a bug in React DevTools which erroneously displays highlighted re-renders.

False positives with "Highlight Updates"
https://github.com/facebook/react-devtools/issues/1290

What's occurring here is the wrapped component is getting re-rendered, but not the component your are using connect on.

Upvotes: 0

Aditya
Aditya

Reputation: 801

Most likely there is some problem with your reducer. Otherwise, you can use reselect library for defining selectors that memoize the values so re-render doesn't happen unless the value really changes.

Upvotes: 4

James
James

Reputation: 82096

The use of mapStateToProps in your connect() call means you want your component to be notified when the store changes - this will happen regardless of whether the small fragment you are interested in has changed or not. Further to this, react-redux prevents unnecessary re-renders itself by performing a shallow comparison on the object returned by mapStateToProps and the previous props.

Looking at your example, scenarios like this newProp: [] would create a new array each time therefore would fail a shallow comparison because the arrays are different instances.

Should I worry about this unnecessary rerenders?

React takes care not re-rendering components unnecessarily, so even if render is called again, as long as the props to said component haven't actually changed then React won't do any additional work. It's probably safe to say that, for the majority of applications, unnecessary re-renders aren't all that much of a concern.

If you feel it will affect your application or you just want to know more about ways to reduce it then there are plenty of material on the subject of performance:

Upvotes: 5

Doğancan Arabacı
Doğancan Arabacı

Reputation: 3982

Connecting your component with the store means 'Call my conmponent or component's render method when props changed'. Default comparison is by simple equality check, which is probably false in your data.

So, in your application, it's highly possible that you created new objects or arrays even if it was not necessary. That's the first and bigger problem you have.

Even if your component needs to re-render, it'll execute render method but your shadow dom will be same leaving you with no expensive operations in most of the cases.

You might do below steps:
- Don't create unnecessary new object and array references. Well, this is proper and longer solution
- Implement your own equality check in with mapStateToProps. There are nice ways to optimise your selector logic but it's depending on your application's details. Better follow this post here: https://medium.com/practo-engineering/avoiding-re-renders-in-react-and-optimising-mapstatetoprops-with-reselect-6e199fa7bc73

Should I worry about this unnecessary rerenders?

It really depends on how big your application is. You should probably have some benchmarking, check some react performance tools.

Upvotes: 3

Maarten Peels
Maarten Peels

Reputation: 1022

You can use the component lifecycle method shouldComponentUpdate, this method gets passed the nextState and nextProps. With this, you can decide if the component needs updating by returning true (update) or false (don't update).

Documentation: here.

Upvotes: 1

Related Questions