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