4

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 ?

5
  • A way to control the re-renders is to convert the Component to a class component and use shouldComponentUpdate to control when it re-renders. Commented Jun 18, 2019 at 10:43
  • are you sure it's your component rerendered not wrapper created by connect() HOC? to check that just set breakpoint in your component's render() Commented Jun 20, 2019 at 12:26
  • 2
    Can you show how your $$data.select.items() selector is implemented? Commented Jun 26, 2019 at 5:15
  • @Aditya $$data.select.items = (state) => state.data.items; Commented Jun 26, 2019 at 8:17
  • Selector looks ok then.. How did you confirm that rerender actually happens? It seems like @lux's answer is worth of checking. Did you try to add some console.logs to render-functions to see what's actually called? Commented Jun 26, 2019 at 21:07

5 Answers 5

5

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:

Sign up to request clarification or add additional context in comments.

Comments

4
+25

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.

Comments

3

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.

2 Comments

but connect already makes shallow equality check, does not it? reactrocket.com/post/react-redux-optimization
It does but if your case is to complicated (copied objects, too deep objects, too big objects to compare), you should come up with your implementation. There is performance cost for comparison and re-rendering. Depending on your cases, shallow, deep, strict or custom equality checks can be used. Or maybe re-render is so cheap that you don't care about proper equality check
1

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.