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.
That ambiguity/indirection and conflict potential can be solved by namespacing the HoC:
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
Render Props does have the benefit in that you can sprinkle it into a render function. M_y_ 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.
<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
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