Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React.PureComponent not implementing shouldComponentUpdate

Tags:

I might be missing something, but I have a component like this

export default MyComponent extends React.PureComponent {
    // ...
}

When MyComponent is part of another components render method, MyComponent re-renders every time the parent renders, even when the props/state are unchanged. So it seems changing from React.Component to React.PureComponent did not make the component "pure".

I tried adding

console.info(this.shouldComponentUpdate)

inside the one of the components methods, and it says it is undefined. Isn't React.PureComponent supposed to add a shallow-comparing shouldComponentUpdate method?

This has now happened with React 15.5.4 and 15.6.0

like image 240
henit Avatar asked Jun 14 '17 06:06

henit


1 Answers

A PureComponent doesn't declare the shouldComponentUpdate directly. You can't visit it with this.shouldComponentUpdate. In the React source code there is a shouldUpdate variable:

(the source code below is simplified)

// default is true
var shouldUpdate = true;

if (inst.shouldComponentUpdate) {
  shouldUpdate = inst.shouldComponentUpdate(
    nextProps,
    nextState,
    nextContext,
  );
} else {
  // if it's a PureComponent
  if (this._compositeType === ReactCompositeComponentTypes.PureClass) {
    shouldUpdate =
      !shallowEqual(prevProps, nextProps) ||
      !shallowEqual(inst.state, nextState);
  }
}

// ...

if (shouldUpdate) {
  // re-render ..
}

Since it's just shallow equal, the code bellow returns false and you get a re-render:

const propA = { foo: 'bar' }
const nextPropA = { foo: 'bar' }

shallowEqual(propA, nextPropA) // false

So use objects and arrays carefully. To prove that PureComponent works, see this example (v15.6): https://codepen.io/CodinCat/pen/eRdzXM?editors=1010

Clicking the button won't trigger Foo's render:

enter image description here

Here is another example that PureComponent may not work for you: https://codepen.io/CodinCat/pen/QgKKLg?editors=1010

The only difference is <Foo someProp={{ foo: 'bar' }} />

Because { foo: 'bar' } !== { foo: 'bar' }, React will re-render every single time. So writing inline objects and arrays in props directly is not a good practice. A common mistake is writing inline style:

<Foo style={{ color: 'pink' }} />

In this case Foo will always re-render even if it's a PureComponent. If you are facing this problem you can simply extract and store the object somewhere, for example:

const someProp = { foo: 'bar' }

<Foo someProp={someProp} />

Since someProp === someProp, the PureComponent works.

like image 88
CodinCat Avatar answered Sep 21 '22 17:09

CodinCat