Solving the problems of Higher Order Components without throwing the baby out with the bathwater

October 10, 2017 0 Comments

Solving the problems of Higher Order Components without throwing the baby out with the bathwater

 

 

There have been some criticisms laid against Higher Order Components in recent articles — specifically “indirection” and “naming collisions”, that aren’t actually problems inherent with the HoC pattern, but are rather usage errors that can be easily avoided.

Here is recompose’s withState HoC

There’s no confusion about where the props counter and setCounter come from, and since you’re in control of what to name the props, collisions are also not a problem.

Let’s apply the same principle to the withMouse example taken from Michael Jackson’s Use a Render Prop!

Since you are declaring what to name the prop you are about to receive right where it’s being used, there’s no issue of indirection or collisions.

Imagine that the withMouse HoC returned two props - position, which contains the x and y coordinates, and changeCounter, which keeps track of the number of times the position has changed.

Requiring each prop to be explicitly named would make the HoC more cumbersome to use with each additional prop that it provides. But without explicitly naming the props, you might end up with something like this:

You could only guess that the position and changeCounter props came from withMouse and not the other HoCs, and you’ll have to assume that none of the other HoCs return props with the same names.

You could go even further and namespace all the HoCs (this works with any HoC that returns props)

Props are now traceable via namespace back to the HoC that provided them, and since namespaces are set when an HoC is being composed, collisions can be avoided as well.

The code for the namespace function is actually really simple

Credits to Jeffrey Burt for the initial code solution and Ivan Starkov for making it more readable

Here’s a sandbox with it all together

Render Props does have the benefit in that you can sprinkle it into a render function. My friend Alex Wilmer has a great example demonstrating the utility of this that I hope will be turned into blog-form soon, but in the mean time here’s a simpler and more contrived example —

Let’s say you’re inside a large-ish block of JSX and there are some hardcoded and repeated variables (in this case, “Eastasia”) that you would like to DRY up.

You have a few options.

  1. Declare the variable up at the top of the function (which adherents to “declare variables close to where they are used” may not like)
  2. Create a separate component and pass the repeated values in (which is somewhat of a hassle)
  3. Create a component called <Assign/> that we can assign values to via props, then receive those values back in the render function.

Let’s go a little further and say that the values would come from async requests. You could make a <Resolve /> component that does this…

Find the implementation of the &lt;Resolve/&gt; component at https://codesandbox.io/s/w8vp4k2pw

I’m not actually sure if using these components is a good idea (consult your nearest thought leader 😄), but it demonstrates where Render Props would allow a certain flexibility that, to my knowledge, HoC would not.

We seem to go through stages of

  1. “Huh, I didn’t realize you could do that”
  2. “This seems to be a great solution” (for certain use-cases)
  3. “This is the objectively superior solution!”
  4. “There are tradeoffs and pitfalls. Here is where this solution makes more sense, here is what you need to be careful about, and here is when it’s better to use something else.”

I think we’re at Stage 4 with Higher Order Components, there are traps that you could fall into, but also solutions to them as well. With Render Props, the articles I’ve seen so far seem to be still between Stage 2 and 3.

Everything is a tradeoff. I’m suspicious of a solution that’s presented as all benefit and no cost — that usually just means the costs haven’t been discovered yet 😄

Feel free to fill me in in the comments on what I’m missing, discuss on reddit, or tweet at me @CheapSteak

This article is sponsored by npmcharts.com 📈
Compare npm package download counts over time to spot trends and see which to use and which to avoid!

Here’s an interactive download chart for recompose


Tag cloud