6

I am now using shouldComponentUpdate but I cannot simply do prevProps.myPropObj == this.state.props.myPropObj to compare. It is an object and I would need to do deep compare. Does react expose to me some method to tell me if my prop changed or not? Or do they expect me to do the deep comparison myself? I was thinking react specializes in this comparison so it should tell us true/false on if same or not no?

hippietrail
  • 15,848
  • 18
  • 99
  • 158
Noitidart
  • 35,443
  • 37
  • 154
  • 323

2 Answers2

6

If the props are immutable, you can use react's shallowCompare. The props can be immutable if you use something like immutablejs, or you change the objects by replacing and not mutating them, for example const prop = Object.assign({}, prop, { changedValues: 'value' });

var shallowCompare = require('react-addons-shallow-compare');
export class SampleComponent extends React.Component {
  shouldComponentUpdate(nextProps, nextState) {
    return shallowCompare(this, nextProps, nextState);
  }

  render() {
    return <div className={this.props.className}>foo</div>;
  }
}

For non-es6, non-node environment:

The equivalent of var shallowCompare = require('react-addons-shallow-compare'); is var shallowCompare = React.addons.shallowCompare; so complete example would be:

var SampleComponent = React.createClass({
  shouldComponentUpdate: function(nextProps, nextState) {
     return React.addons.shallowCompare(this, nextProps, nextState);
  },
  render: function() {
     return React.createElement('div', {className:this.props.className}, 'foo');
  }
});
Noitidart
  • 35,443
  • 37
  • 154
  • 323
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • Does shallow mean it only checks the immedidate number/string/boolean entries? If it sees an object does it skip it? – Noitidart Apr 20 '16 at 12:27
  • 2
    It checks the immediate children of the props, If they are objects or arrays, it just compares the references. That's why you need to replace and not mutate your object and arrays props. – Ori Drori Apr 20 '16 at 12:30
  • Ah perfect! I only do setState by doing `var newObj = JSON.parse(JSON.stringify(this.state.obj)); this.setState({obj:newObj})`, no matter how deep my object is, does this qualify as immutable? – Noitidart Apr 20 '16 at 12:32
  • 1
    Yep. You're creating a new object of the old. There are new and better ways to do it, but this qualifies. – Ori Drori Apr 20 '16 at 12:33
  • This is a perfect solution thank you very much! May you please verify my non es-6 version I posted below, if it is correct may you please add that to your solution. Also may you please link me to the alternatives to `JSON.parse(JSON.stringify(...))` its a lot of typing on my part haha – Noitidart Apr 20 '16 at 12:35
  • This [QA](http://stackoverflow.com/questions/36553129/what-is-the-shortest-way-to-modify-immutable-objects-using-javascript-es7-spread/36553238#36553238) contains several ES6 and ES7 methods. You can use immutablejs or seamless immutable, or lodash for Object.copy / assign. – Ori Drori Apr 20 '16 at 12:45
3

React does not provide deep comparison of objects out of the box.

You could build something yourself for this. E.g by adding and maintaining 1 unique ID to your object to register changes.

Or use a library like immutableJS consistently across your app. Worthwhile for large complex app with large complex objects.

To make sure: for the functionality of your app, you should not need shouldComponentUpdate(). React has its own engine that only renders differences between states.

wintvelt
  • 13,855
  • 3
  • 38
  • 43
  • Thanks for this insight, it's giving me questions to help me understand React a lot more. Doesn't the last sentence here conflict with the stuff we discussed in this topic: http://stackoverflow.com/q/36741540/1828637 - on `componentDidUpdate` constantly triggering? Or is it that the DOM will never update really even though the `componentDidUpdate `is triggering – Noitidart Apr 20 '16 at 12:52
  • 1
    `componentDidUpdate()` runs after render cycle, even if render did not result in DOM change. If in one round prop = A: then react will render component to DOM. If in next round prop is passed, value still A: react will run re-render cycle (but will not change DOM, because nothing changed), and WILL run `componentDidUpdate()` afterwards. If you have implemented `shouldComponentUpdate()`: in next round react will first check `shouldComponentUpdate()`, which will return false. Then render cycle is aborted and `componentDidUpdate()` will NOT run. – wintvelt Apr 20 '16 at 13:12
  • Whoops I was away for a bit, back to to see that answer, than you very much! So I'm not sure what you mean by the last sentence in this above solution. You mentioned that `shouldComponentUpdate` should not be needed. Does this mean that `componentDidUpdate` should not be needed, and only if I do use `componentDidUpdate` then I will have to use `shouldComponentUpdate` or somethign to check check if it really changed? Thanks for your patient explaining. I'm loving React just trying to understand it. – Noitidart Apr 20 '16 at 14:25
  • 1
    What I mean is that the output from code including `shouldComponentUpdate()` should be exactly the same as output from code without that method. `shouldComponentUpdate()` is for faster output, not for different output. For `componentDidUpdate()`, maybe [this post](http://stackoverflow.com/a/30529826/5358807) will clarify. – wintvelt Apr 20 '16 at 17:05
  • Ahhh for faster and not for different output, thank you! I understand! So what I really should do is within the `componentDidUpdate` I should do the `shallowCompare`? – Noitidart Apr 20 '16 at 18:32
  • 1
    Is `shallowCompare()` the appropriate method? That depends on your object. See @OriDori's answer. Is `componentDidUpdate()` the right place to compare? That is another question. Answer depends on what you want your code to do with the outcome of the comparison. – wintvelt Apr 20 '16 at 18:53