ciaoben
ciaoben

Reputation: 3338

Why should I avoid to use _.isEqual in shouldComponentUpdate

I have read this question many times and everytime the suggested answer is to not use deep comparison because it is costly. I have tried to implement this in my application and it seems very fast indeed.

  shouldComponentUpdate = (nextProps, nextState) => {
    let a = +new Date();
    let equalProps = _.isEqual(this.props, nextProps);
    let equalState = _.isEqual(this.state, nextState);
    let b = +new Date();
    console.log("----> deep equality navbar took ", b - a, " result = ", equalProps && equalState);

    if (equalProps && equalState) return false;

    return true;
  };

And here is a sample of log produced:

----> deep equality msg list took  0  result =  false
----> deep equality msg list took  0  result =  false
----> deep equality navbar took  0  result =  true
----> deep equality sidebar took  0  result =  true
----> deep equality msg list took  1  result =  false

Basically, it seems to never go over the 1 millisecond, and I am dealing with some 6/7 levels nested objects. The render of the message list takes over 70ms normally.. I can avoid easily with a function call that takes less than 1ms.

I am missing something big here? It seems almost to be good to be true.. roast me :)

Upvotes: 1

Views: 3653

Answers (2)

Matt Carlotta
Matt Carlotta

Reputation: 19762

Instead of comparing a large data set to itself over and over on state or prop change, you could simply utilize and compare against a date object to let the component know if it needs to be rerendered. For example, a retrieved date object could be updated if the messages data changes; now, instead of a large data compare, it can be compared against itself:

class MessageList extends Component {
  state = {
    retrieved: {},
    messages: [],
    err: ''
  }

  fetchMessages = () => {
    this.props.fetchMessages()
    .then(({data}) => this.setState({ messages: data, retrieved: new Date() }))
    .catch(err => this.setState({ err: err.toString() })) 

  shouldComponentUpdate = (nextProps, nextState) => (
    nextState.retrieved > this.state.retrieved || nextState.err !== this.state.err 
  ) // this would compare a retrieved date and/or an err; it will only rerender if either has changed

  render = () => ( ... )

 }

This will remain consistent across browsers and different devices, even if your application scales up to include more data, more props, and more state.

Upvotes: 0

nilesh bhingaradiya
nilesh bhingaradiya

Reputation: 311

It is because you are using small sample data so you did not find any speed issue, if there is big data to compare then it will big issue because componentshouldupdate run on every state Update so if lodash.isEqual takes some time it will slow down react page render speed

you can see below a list of object compare and find batter one you project

fast-deep-equal x 226,960 ops/sec ±1.55% (86 runs sampled)
nano-equal x 218,210 ops/sec ±0.79% (89 runs sampled)
shallow-equal-fuzzy x 206,762 ops/sec ±0.84% (88 runs sampled)
underscore.isEqual x 128,668 ops/sec ±0.75% (91 runs sampled)
lodash.isEqual x 44,895 ops/sec ±0.67% (85 runs sampled)
deep-equal x 51,616 ops/sec ±0.96% (90 runs sampled)
deep-eql x 28,218 ops/sec ±0.42% (85 runs sampled)
assert.deepStrictEqual x 1,777 ops/sec ±1.05% (86 runs sampled)
ramda.equals x 13,466 ops/sec ±0.82% (86 runs sampled)
The fastest is fast-deep-equal

https://github.com/epoberezkin/fast-deep-equal

Upvotes: 2

Related Questions