Render Props and You — A Love Story

That sweet, sweet composability ❤

Hi all! I’m back to tell y’all about a new thing I’ve been playing with. If you keep up with the React world, you’ve probably heard some very well known people talking about Render Props. Today we will dive into them a bit and see how they can make your components simpler and more reusable!

wtf is a render prop?

A render prop is exactly what it sounds like: a prop you pass to a component that tells it what (and/or how) to render. There are a bunch of libraries that take advantage of this pattern (react-motion, react-router, even React’s new Context API) use them.

wtf does it look like?

A simple example of a render prop could look something like this:

class Wrapper extends Component {
constructor() {
super();
this.state = { name: ‘Bryan’ };
}
render() {
return this.props.render(this.state.name);
}
}
const Name = () => (
<Wrapper render={name => <h2>Hi, {name}!</h2>} />
);

Now when we use the Name component, we can pass a prop called render. The argument we receive here is the name state. This is a great way to make a reusable component that accesses the same bit of state (say, a user’s name, for example), without needing to render the same thing every time.

Functions as children

It’s easy to forget, but React really is just Javascript, and this.props.children is no different. Using the same pattern as above, we can refactor this a bit more to make it even easier to reason about and read. Instead of passing a prop called render, what if we just expected the props children to be a function? That means the child being rendered could still have access to the state that is in the wrapper, too! Children being a function is a render prop too. They don’t need to be explicitly called render, only used to render the component.

class Wrapper extends Component {
constructor() {
super();
this.state = { name: ‘Bryan’ };
}
render() {
return this.props.children(this.state.name);
}
}
const Name = () => (
<Wrapper>
{name => <h2>Hi {name}!</h2>}
</Wrapper>
);

Hopefully you are beginning to see how powerful this pattern can be for removing duplicate code from your projects. Let’s work through something a bit bigger to see how you might use it in a real project, not just a name printer ;)

A Shopping Cart example

In this example, we will make a small shop. Perhaps we are selling silly hats? There will be a component we will use the above pattern for to fetch data and set our loading state.

Thinking through this application, we will need a front page which contains all the items in our store. Seeing as we are just getting this store off the ground, there will only be 4 items in this store.

Clicking on one of these items should open up a details modal. This could contain details of each hat, and maybe a picture.

Finally, we will need a wrapper component which will fetch our data for us from our server We wont be using real data in this example, we can get away with timeouts to show how it will work. You can swap these calls out with network calls if you’d like :)

Here we have the components without any frills, just plain old React state and rendering with JSX like usual:

A bit of cool stuff going on here — We are using a Fragment in App.js. This is a utility of React which lets you wrap components with something to ensure there is only one child, but will not render anything to the DOM. This saves us from using unnecessary div’s or other wrapper elements to keep our DOM render cleaner.

Other than that, this is a pretty simple application. We call FrontPage.js which maps over whatever data we pass to it, rendering each SingleItem containing info on it. Clicking on a SingleItem will open up the ItemDetails modal, where we will (eventually) be fetching more data to load asynchronously.

Writing a DataFetcher component

Now the fun begins! What we want to do is write a wrapper component we can use to fetch data (normally from a server, but we will be faking it for this example). This component can track when the data is loading, handle passing the data down once fetched. This is really cool because once we write it, we can use it wherever we want! We can use this same component to load the list of our data we are passing into FrontPage as we use with ItemDetails!

First we just want to make a component which takes a function as a child and renders it, passing in the relevant bits of state. These bits of state be a loading boolean and whatever shape your data will take. We will also write a fake fetch method that sets hard-coded data after a timeout (to fake an async call). We wont do it here, but you could also catch any errors during the fetch and pass them along with the loading and data props for nice, consistent error handling.

Now, we can use this same data fetcher in our FrontPage component AND in ItemDetails! Even though they are fetching different data (and possibly even differently shaped data!), we can handle all that logic here and make the components that use that data simpler. Rearranging App.js, we can wrap the FrontPage in DataFetcher like so:

// src/App.js
<DataFetcher data={SAMPLE_DATA}>
{({ loading, data }) => (
<FrontPage
loading={loading}
data={data}
showDetails={this.showDetails}
/>
)}
</DataFetcher>
// …

Changing FrontPage to be returned from the function depending on the value of loading is a very powerful pattern that can greatly increase code readability and code re-usability.

We can even change only a small part of a component based on the state of the data fetch. In ItemDetails:

Above, we are still rendering the title and details of each item, even when we are in the middle of getting new data from our server. Once the data loads, we replace the “Loading…” section with our brand new data!

This pattern could continue to be used all across the app. If you have ever written components with quite a few similar methods, this may be an excellent sign to try to make one component more generalizable, like we did above.


Hopefully this little write-up helped clear up what Render Props are, and gave you a good idea of how they may benefit your app and/or code base. Let me know if there is anything I can clarify, explain more, or something else you’d like me to go over! You can reach out in the comments below or on twitter at @spacebrayn