Reputation: 602
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
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
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
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
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
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