Quick-gun Morgan Quick-gun Morgan - 24 days ago 5
React JSX Question

PureComponent's shallowCompare is not working as expected

I am trying to avoid unnecessary re-rendering of a child component (Review) by extending it from PureComponenet.

This component is being called from the parent component (Reviews), which is not a PureComponent.

By debugging I am seeing that whenever a change occurs to one of the review, all the reviews related to that product are getting re-rendered. Obviously Reviews' props gets updated and it passes individual Review's relevant props to individual Review components.
where I am also seeing this,

nextProps.reviewer === this.props.reviewer_info -> false
nextProps.reviewer_info = []
this.props.reviewer_info = []


I believe that pureComponent uses shallowCompare and it should return true while comparing 2 empty arrays, is that correct?

Does my parent component also needs to be a PureComponent in order to stop unnecessary rendering of my child components? Is that the missing part?

My review component has other child components, which I know also should be declared pureComponents. (I will update them but does this stop Review component from achieving pureComponent's benefits?)

Or above 2 are not the correct reasons for the re-rendering in-spite of using pureComponent and I am missing some other part?

Answer Source

Does my parent component also needs to be a PureComponent in order to stop unnecessary rendering of my child components?

No, that's not necessary.

I believe that pureComponent uses shallowCompare and it should return true while comparing 2 empty arrays, is that correct?

It is not. The shallow comparison uses === to compare the old and new value of each property on props and state. But as you can see in a browser console [] === [] is false. This is because each [] expression creates a new array object that is unequal to the others.

As a consequence, a simple array or object literal in a property (e.g. <Review prop={[]}/>) will trigger a rerender of Review whenever Reviews is rendered, negating the effect of the PureComponent.

To enjoy the optimized behavior, you will need to make sure that each non-primitive prop keeps referring to the same object instance as long as its value doesn't change (e.g. by keeping it in Review's state). Furthermore, if there is a change, you will need to create a fresh top-level object for that prop, rather than modify the existing one in-place (so don't use push or assign directly to the prop objects properties.) The immutable-js package can be helpful with this, but es6 spread operators often work fine as well.

My review component has other child components, which I know also should be declared pureComponents. (I will update them but does this stop Review component from achieving pureComponent's benefits?)

It shouldn't affect Review (unless you create the children in the render method of Reviews, like <Review ..>..<Child ../>..</Review>, in which case props.children will change every time and trigger rerendering.)