Simplifying life with React render callbacks

Adam Rackis
3 min readApr 10, 2017

--

I recently attended the Advanced React workshop by Ryan Florence, of ReactTraining.com. This post is my best attempt to distill some of the coolest parts he covered, though I can pretty much guarantee I won’t come close to the real thing; I’d urge any React devs out there to have your boss send you to the next one that’s in town. You’ll learn a ton, and have a blast doing so, I promise.

React offers a number of ways to have one component wrap another, for the purpose of passing state down. In this post I’ll go over all the ways I know of, discuss some pros and cons with each, and in the end introduce what might be a novel approach: render callbacks.

The use case

Let’s create a component which renders some content, passing along … the current time. A less silly example might use stock ticker values, geolocation data, etc.

So the idea is, I’ll render thisCurrentTime component with a child in it, and that child component will receive the current time as a prop. The current time component will look something like this

Of course that will render military time, and not really format single digits decently, but who cares :)

And we’ll want to use it like this

The rest of this post will explore ways in which we could make CurrentTime such that this would work. Here goes!

Just clone the children

The most straightforward way would be to just clone the children passed into CurrentTime, like so

So now CurrentTime just takes in whatever child component you pass it, and clones it for the purpose of passing in an additional time prop. This works, but it bloats our markup a bit, and it also forces us to make a new component; something like this wouldn’t work

Higher order component

What if we can take an existing component, and add in (not mixin!) the ability for it to just sort of automatically have the same time prop passed in.

Enter the higher order component;

Now currentTime is just a function. It’s a function which takes in a component, and then returns a NEW component whose only job is to render the original component, with the same props, as well as a new time prop.

If you see the decorator up there, @currentTime , note that we could have just as easily done something like

But I much prefer the simplified syntax, which obviates the need for the explicitly defined, intermediate component.

One thing that’s been constant so far is that we’ve always had to create a fresh component each time; just rendering an inline div would never work, because we’d have no way to get to the time prop. We also had some coupling with our component hierarchy: we always need the component who’s receiving the time to be the child. Let’s see if we can simplify this some more.

Render callbacks

What if, instead of passing a component for the child to CurrentTime, we just passed a function. And what if that function was passed the time value. Wouldn’t we be able to achieve the same thing, but more flexibly? Yes! Let’s see what that looks like.

We rendered an actual function as the children of CurrentTime. This gave us a callback with the time value we wanted — now we can do whatever we want with this value.

Can we have the best of both worlds?

What if sometimes we want a nice callback like this, but sometimes we just want to throw in a component as the child? Simple: support children like we did before, but also support a render prop on our CurrentTime component. Let’s see what that looks like

So now CurrentTime can take a render prop, of it can take a more traditional component child.

Are there any downsides?

Using callbacks like this to render content is fantastic, but are there any downsides? It would seem to me pushing this too far might make for a more awkward dev experience. For example, when using Redux I’d much prefer to just connect my components like this

and then render them as needed, rather than force that code into inline functions in the middle of my JSX. But YMMV. Happy coding!

Hit me up on Twitter if you have any comments— Medium’s commenting system is terrible.

--

--