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
There’s no confusion about where the props
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
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
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
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.
- Declare the variable up at the top of the function (which adherents to “declare variables close to where they are used” may not like)
- Create a separate component and pass the repeated values in (which is somewhat of a hassle)
- 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…
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
- “Huh, I didn’t realize you could do that”
- “This seems to be a great solution” (for certain use-cases)
- “This is the objectively superior solution!”
- “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 😄