React helper-order components 💪🏼

Higher-order components are great. All of the benefits of mixins, without the headaches. I also find them helpful for quick and dirty debugging, troubleshooting, and performance analysis. Let’s explore a few examples of using helper-order components to make your job a little easier.

A perfect match with stateless functions 💍

Higher-order components are particularly helpful for quickly checking behavior of components that are stateless functions, because they can be easily added without changing the function itself (like changing to a class).

Say you have a CoolButton:

To peek at the props you change the function:

With a helper-order component, however, the footprint is smaller (the change is temporary so require is used inline):

For reference, here is a very basic implementation of logProps:

Even better when already using higher-order components 👏🏾

If already using other higher-order components, especially with a utility like recompose, using logProps might require even bigger changes. Consider CoolButton in recompose:

Using the approach above, compose, withProps, and renderComponent would need to be unrolled and re-rolled when finished. A helper-order component requires just one additional line in the compose() pipeline:

Another example—counting renders ⏱

Say you’re making a game with a bunch of draggable Pieces (in this case, circles), which change color while being dragged:

The complexity of drag implementation is being hidden within draggable, but suffice it to say that components are wrapped in an element that is positioned to its current drag coordinates. It is also given an isDragging: boolean property indicating the drag status.

The Pieces are placed on a Board:

With a few pieces everything is fine, but with many pieces drag performance becomes noticeably choppy. Only the coordinates of the dragged object are updated on each step of the drag movement, so ideally only the dragged Piece is re-rendered. Given the performance you surmise that the other Pieces are re-rendering as well. Profiling could be done in a few ways, but very quick and easy way is to log renders:

I did this in on a relatively complex example with many drag areas and pieces, and got the following output for just one small drag movement. Clearly there is a problem:

Fortunately this is an easy problem to fix—we are able to use pure to let React know the Pieces do not need re-rendering unless the props change:

Immediately the output shows a huge improvement for the same action, and performance is great again:

For reference, here is a very basic implementation of logRender:

And here is a slightly better version that keeps track of the count as shown in the example above:

It should be noted that this only works for counting renders caused from the outside by prop updates. Stateful components updating their own state (or calling forceUpdate()) wouldn’t cause the helper to re-render and thus the count won’t be updated.

General tips

Whatever helper you create, here are a few tips to keep in mind:

  • Helper-order components can accept arguments, which you can use to make them more focused. For example, my version of logProps accepts a selector, which can be the name of a single prop, a list of props, or a function. If present, only props matching the selector are output.
  • Use WrappedComponent.name to make it easier to determine where the output is coming from.
  • Use JSON.stringify when logging objects to make it easier to see quickly without the need to expand manually.
  • It’s handy to adopt a standard syntax whereby adding helper/higher-order components requires minimal change:

Now HOCs can be added just at the export line. Or to make it even easier:

The audience is us.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store