How Render Props Differ From Functional Components

Jacob Friedmann
4 min readOct 4, 2018

--

Today, in discussion with a coworker, I realized that while I have been using the React Render Prop pattern for some time there was still a gap in my understanding. The initial question that stumped me was “how does passing a component class/function differ from a render prop”? I turned to Reactiflux (the React discord) to see if I could find an answer.

My initial question posed to the Reactiflux group

As I expected, the group swiftly provided an answer.

NickServ opening my eyes

This explanation was a bit of a “lightbulb-moment” for me, so I decided to expand on this with more details.

Separation of Concerns

The motivation behind the render prop pattern is the separation of concerns between state management and render logic. Doing this allows for reuse of state management in different form-factors (like HOCs or mixins before them).

Let’s look at an example: a simple counter component.

This component both manages the “count” state and also decides how it should look. We would then use this component in our application as follows:

Now imagine we want a second counter on the page, but this counter we want to be fancy. Our first attempt to do this might be to create a <FancyCounter /> component that looks something like this:

What we notice about this component is that most of the code is duplicated from the initial counter. However, if we were to separate out the state management from the rendering logic that would no longer be the case.

Our first attempt to do this might use a prop that takes a React component class or function.

We could then implement a <SimpleCounter /> and <FancyCounter /> as follows:

This reduces the duplication of our code and works pretty well for this scenario, but we will soon reach a point where this pattern will no longer work.

Dynamic Composition

Imagine we want to make our <FancyCounter /> configurable by giving it additional props.

There is no easy way using the current pattern for us to pass the additional color prop. We could potentially modify our state container to take in additional props for the counter component, but this approach is rather clunky.

We could then pass the color prop to the <FancyCounter /> from the parent component.

While this is workable, a cleaner approach that doesn’t rely on counterProps could use an inline functional component instead.

While this approach looks much cleaner and clearly allows for dynamic composition, there are performance concerns that might not be obvious (as in this is the part that I could not for-the-life-of-me figure out!).

Inline Component Performance Problems

To understand why the approach of using an inline functional component is less than ideal, let’s take a look at the rendered React element tree after the first render.

An instance of our functional component that we’ve defined inline (in the render function) appears in this tree as <AnonymousInlineCounterComponent1/>. This intermediate component is created within the <CounterContainer/> component because the Counter prop is pointing to an anonymous function. In other words, when we write <Counter />, what we are really saying is React.createElement(Counter /* An inline anonymous function */).

Now, the second time render is called a new anonymous function will be created. This means that the React element in the tree is now based on a new anonymous component.

When React starts to reconcile this new tree against the old one it will compare <AnonymousInlineCounterComponent2/> to <AnonymousInlineCounterComponent1/>. Because these two elements are instances of two different components (anonymous functional components), React will stop at this part of the tree and re-mount everything below it even if nothing has actually changed.

Render Props

If we refactor our <CounterContainer /> component to use the render prop pattern, we can prevent this intermediate component from de-optimizing the React component tree. In other words, we treat the inline function as a function instead of as a React component.

This requires only a small refactor to the usage of that component (changing the prop name).

Now, the React element tree will no longer have an intermediate component:

This in turn means that subsequent renders will no longer unnecessarily re-mount the <FancyCounter /> and its children.

To see code that illustrates this issue, check out this “benchmark” repository. There is also a live demo of the “benchmark” here.

I hope this helps to explain some of the motivation behind and implementation of the Render Prop pattern. This is something that was bothering me for some time and to finally wrap my head around it feels good!

--

--

Jacob Friedmann

Building, teaching, and learning about software: JavaScript, React, front-end platform at Rover.com