When working with React, code reusability is one of the problem that we often have to face. Being a library that promotes component-based pattern, it is only natural to build reusable components. Whether you are writing a library, an npm package, or a web-app, code reusability is something to strive for.
There is a lot of opinion, and with it, solutions, regarding code reusability. One of the most common way is to use the Higher-Order Component pattern (widely known as HOC). But recently, another pattern seems to start getting traction as well, it is called (you guessed it) Render Prop. In this writing, we are going to write a component using this pattern to help us understand the pattern.
The code that we are going to use is available in this repo.
What is render prop?
Let’s start by taking a look at what the official React documentation has to say about this:
Simply by reading that description, it might not be obvious enough as to how exactly do the components ‘share code’ using this pattern.
There is actually already an example in the official React documentation, but heck — , why not do another one as a practice? We are going to write a component for fetching data from an API.
The data: xkcd comics
The API is simple enough, we just need to send a GET request to this URL scheme:
and it will return a response like this:
"safe_title": "USB Cables",
"alt": "Tag yourself, I'm \"frayed.\"",
"title": "USB Cables",
Fetching data from API, the most basic way
Let’s say we have a component named
Comic. Without using packages, normally we would do our fetching in the
componentDidMount() cycle. We would then update the state of our component based on the response from the API. Then, we would probably want to render something based on those values. Something like this piece of code below.
The code works, no problem.
But, what if there is another component that also need to fetch data from some API? Do we also create a new component that do the fetching part in the
componentDidMount() cycle as well?
While that is definitely going to work, by doing it that way, we are actually rewriting the same logic, the logic that is actually reusable.
So, what can we do to make the fetching part reusable?
With the render prop pattern
We have already established the fact that more than one component need to do fetching. So, our mission, should we choose to accept it (of course we do!), is to make a separate reusable component that will handle the fetching, and then passes the data and other needed values back to the
As you can see in the code for
Fetch component, the component expects to receive an
url to fetch, and also a prop named
render. The component will fetch the
componentDidMount() and then setting its own state based on the response. Notice that the component doesn’t render any element in its
render() function, it simply called
this.props.render (the render prop!) while passing
this.state as an argument. The prop doesn’t need to be named
render, though. What matters is the prop is a function that decides what the component should render.
We should update our
Comic component to utilize our newly made, reusable
We can see that in
Comic is rendering the
Fetch component, while passing down
this.renderContent as the render prop. Remember that
Fetch will invoke
this.props.render(this.state). By doing this, the
Fetch component is essentially exposing its own state to
this.renderContent. This means that
Comic now have access to
Fetch's state in
What’s the point of doing this?
We succeed in taking out some pieces of code that do the fetching logic to a separate component. The component can also be used in other components that need the same logic as well. In other words, we succeeded in writing a reusable component!
Correct usage of the render prop pattern can help us to write code that is reusable, while still being relatively easy to read and understand as well. There are a lot of cases in which this pattern can be useful, but it might not be obvious at first glance. By practicing the use of this pattern more often, we can be better at recognising places where this pattern can be implemented, and thus, improve our code.