'Extend PureComponent' was quoted out of context. The documentation says the opposite,
Only extend PureComponent when you expect to have simple props and state
Because
React.PureComponent’s shouldComponentUpdate() only shallowly compares the objects. If these contain complex data structures, it may produce false-negatives for deeper differences.
React components don't compare props, unless they implement shouldComponentUpdate, like PureComponent. A component can be re-rendered with exactly same prop (=== equal).
If the state is mutated but isn't forced to update (this is an antipattern), children won't be re-rendered.
If the state is mutated and forced to update (this is an antipattern), children are re-rendered:
class App extends React.Component {
componentDidMount() {
this.state.bar.baz = 2;
this.setState(state);
}
...
}
In order to limit updates to deeply changed props, Foo should implement shouldComponentUpdate with deep comparison, e.g. Lodash isEqual:
class Foo extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
return !_.isEqual(this.props, nextProps) || this.state !== nextState;
}
...
}
Since deep comparison may be costly, performance tests should be run to determine whether it provides performance improvements.
Immutable state and props are highly welcome in React because they allow to avoid this problem. If an object changes in some way, it should be replaced with another object, i.e. state update should result in new state and state.bar objects:
class App extends React.Component {
componentDidMount() {
this.setState(({ bar })=> ({
bar: { ...bar, baz: 2 }
});
}
...
}
In this case Foo needs to shallowly compare bar object it receives as a prop, so it can be PureComponent, or React.memo (as another answer explains).