2 things about PureComponent you probably should know.

Anton Korzunov
6 min readJul 23, 2017

--

I hope that you heard that PureComponets, or pure-render-mixin in the past, or shouldComponentUpdate, can improve speed of your application.

Pure something in Pure somewhere.

And I hope that you heard the meanings of Pure keyword in this context.

Pure function will evaluate the same results with the same arguments, and will not produce any side effects (or results MAY be NOT the same).

So pure, pure by any reason and by any technique, component will render the same children with the same props.

That’s how 99.99% of people will understand PureComponent. As a predictable function.

Let’s recall stateless components, which assumed to be a pure function.

But pure functions are not pure components.

Right now stateless component is always impure component. As a result stateless components in many-many cases are slower that stateful components, cos you can optimize “stateful” components, but can’t change the way stateless ones works.

In the same time stateless components are more pure than PureComponents, as long they always do the same job, while PureComponent’s optimization behavior is not pure. Weird, right?

Stateless components (could be) SLOW!

But wait! One said that Facebook promised stateless components to be pure, but not now, may be tomorrow! Yes! Just wait a bit.

That was true for React 15. It is not true for 16

How PureComponents works?

React gives you the ability to optimise component, by implementing shouldComponentUpdate function.

Next, you can decide should you re-render it on props and state change, or not.

Pure-render-mixin or PureComponent just implements this function for you. And it is just impossible to generate it for a stateless component as long it is not a Component. It is just a function.

Or possible? Actually, React uses that stateless component indirectly and it can perform necessary checks in Component Adapter. Actually — stateless components are very complex thing, and React expects them to be pure functions. If not… oh, even don’t try.

So, the only question here might be a bit strange —

Why “purifying" of stateless components is..

..not enabled by default?

How Pure is a Pure component?

The answer lies in math.

if f(X) produces Y, then `f` will be `pure`, when with the same X `f` will generate the same Y.

With absolutely same X will produce absolutely same Y. Including a whole nesting component tree.

So, if you are a PureParent you have to think shouldIUpdateMyself, but also you have to think shouldIUpdateAllMyChildren.

So, you have to be a good parent.

In some situations you can think about direct children, but not for the ALL. Especially if you a just a component, and do not own some necessary knowledge.

And the second problem, that you should not only think about props and state — you also have to think about context. And to think about context you have to declare contextType, so you have to specialize that are you "thinking" about. Imho, it is impossible.

As result, PureComponents will block ANY context changes (they don’t expect).

UPD: Ok, that was true for React 15 context. React 16 context API has nothing with it. It will always work. Always!

Let me write an example.

<MyApp>      // just my app
<Router> // react-router.
<Chrome> // my _pure_ chrome. Just a chrome.
<Switch> // react-router Switch
<Route ....>
</Switch>
</Chrome>
</Router>
</MyApp>

Switch will not work. Haha!

React-router’s Router will store current location in router props of context. And React-router’s Switch will read it back and choose a Route.

But Chrome is a very pure component, and WILL NOT react to context change in Router, cos it isNOT USING those values and should ignore them, cos has absolutely no way to read their values.

You have done well. Everything is correct. But it isn’t gonna work.

That’s why, then you use PureComponent you have to think not for a single component, but for a whole Application.

It is safe to use PureComponents as atoms, ie small and final things like buttons. But it is not safe to use them in chromes, forms, pages and other molecules.

“Not safe”, but allowed and absolutely ok. You have been warned.

Redux connect — is a PureComponent.

Yes — a very important thing, a HoC for a molecule is a pure one. And works even inside other pure components. And gets store from a current context.

Same is working, for example, for styled-component — you can wrap it with PureComponent, but it will still react to Theme changes.

Solution is simple — bypass logic, use old school events bus, subcribe, wait and emit events.

Styled-componets:

componentWillMount() {      
// subscribe to the event emitter. This
// is necessary due to pure components blocking
// context updates, this circumvents
// that by updating when an event is emitted.

const subscribe = this.context[CHANNEL];
this.unsubscribe = subscribe(nextTheme => { <----- MAGIC

React-redux:

trySubscribe() {
if (shouldSubscribe && !this.unsubscribe) {
this.unsubscribe =
this.store.subscribe(this.handleChange); <----- MAGIC
}
}
componentDidMount() {
this.trySubscribe();
}

Thus, even if parent Pure Component will block any update enables you to catch a change, store update, context variable change, or everything else.

So — something inside pure components is very soiled and absolutely impure. It is driven by side effects!

But this bypass straight logic flow, and works just differently from the rest of application.

So — just be careful. And don’t forget about magic.

Aaaand….

And this is a reason, why any redux store update will cause redraw in each connected component, and why you should use reselect just next to connect HoC —

to stop unnecessary change propagation.

But you should read this from another point of view:

  • redux-connect is a source of a change propagation.
  • redux connect is the end of a change propagation. It is still a PureComponent.

And this leads to quite handy thing — you can control change propagation with redux-connect only. Just create a boundaries for a change. Lets talk about this in another article.

This leads to a simple proposion:

If you are not 100% sure that you have “rights” to stop propagation

— DONT STOP IT!!

For example — your children could be defined inside another component(that is a common case!) and could use that component props, visible in their scope. But there is no way “you” could know it.

const App = (props) => (
<div>
<PureComponent>
<AnotherComponent>
<strong>{props.name}</strong>
</AnotherComponent>
</PureComponent>
</div>
);

In this case — “you” have no rights to be a PureComponent and stop updates, just anything could be placed inside, and might dont know — what.

This might become even more severe with render props, as long pure components could lead to different function scopes visible from different function-as-children, as long those functions were memoized(freezed) in the different (sometimes random) renders.

Conclusion

Pure components keep your application fast. Sometimes — more predictable, but often — less predictable, as long they change the way application works. The way it flows.

Stateless components are not pure, and may run slower than PureComponents by any kind. But usually this is not something you should think about. They are made from pure functions and they are predictable.

But… if you very wish to create a fast application with good user experience — you have to use Pure Component, or shouldComponentUpdate (sCU).

And the only way to use them — as a “event propagation boundaries”. Predictable “event horizons” in predictable places. To be the start of any update(as redux or Context API), and to be the end for anything “unexpected”. “Unpredicted”. “Unwanted”. “Unknown”.

--

--