Introduction to higher-order components (HOC) in React
You can find the entire working code here. And a live demo here.
Originally written on my personal blog.
This article is intended to give you an understanding of how higher order components work, and when and why to use them. We would keep it beginner friendly, to help you get a better understanding of the concept and why it exists.
Higher order components, in general, are a functional programming methodology. However, this article does not require any functional programming knowledge but required some basic knowledge in React. We assume that you already are familiar with React, React components, React props , Lifecycle methods and how to build a basic app using React.
We will cover some functional programming concepts that will help you understand HOC in react better.
Let’s begin with the formal definition:
A higher-order component is a function that takes a component and returns a new component.
HOC is not a feature in React or any other programming language, but a pattern evolved from the compositional ( made of components ) nature of react.
Functional programming and higher order functions
A higher order function is a function that accepts another function as an argument. You would have already used the map function which falls under this category.
This is a concept that is derived from the world of functional programming. But why use a functional programming concept in React?
The goal of this pattern is to decompose the logic into simpler and smaller functions that can be reused. A rule of thumb is a function does just one task and does it well. This also avoids side effects ( changing anything that is not owned by the function ) , and makes debugging and maintenance a whole lot easier.
A classic example of functional programming example is the multiplication:
const multiply = (x) => (y) => x * ymultiply(5)(20)
Similarly, a HOC takes another component as argument.
Let’s build a HOC and learn more as we go.
Higher order component in React
Let’s look at some code straight away.
The above example takes a component and reverses the content inside it. reverse
is a HOC, that takes in an element ( name
in the example ), find the content inside that element, reverses it and spits out an element with reversed content.
What shown above is an extremely simple use case for the purpose of understanding the concept.
Two things happen with an HOC
- Takes a component as argument
- Return something
Let’s have a look at a more practical and complex use case.
In all the apps we have created in the past, if we have to load data from an API, there would be a latency involved.
Typically there is a time lag between when the page is rendered and the actual data is shown. Most of the apps show a loading animation to make the user experience better. Let us build a Loading animation component to demonstrate the concept of HOC.
You can find the entire working code here. And a live demo here.
We will refer to certain parts of the repo as we progress. This is a react app made using create-react-app
.
First of all let’s understand how the app works. We use randomuser.me to generate some sample data. Let’s assume that we are building a feed of random users. In App.js
we make a request to randomuser.me
to get some random data. The request will made inside the componentDidMount
function.
The random data from the API is processed since we are only interested in the name, email and the image, we filter it out and set it as the app state. Once we have the data, we pass the contacts
to our Feed
object as
<Feed contacts={this.state.contacts} />
Here is how our Feed component looks. It simply passes the received contact data into FeedItem
. And FeedItem iterates through the data to actually display it.
You would have noticed that the export statement is different from the normal case. Instead of Feed
we export the Feed
component wrapped in a Loading
component.This is because our Loading HOC is a curried function. Currying is the process of breaking down a function into a series of functions that each take a single argument. Read more about currying here.
Let’s take a look at our Loading component.
Let’s understand how the component works step by step.
- For ease of understanding assume component takes another component ( in our case
Feed
component ) along with a propertycontacts
- Now the
Loading
component checks of theloadingProp
( in our casecontacts
)are empty — The functionisEmpty
does this. - If it’s empty the
Loading
component return
<div className="loader" />
We use the classname loader
to add some styles and implement the loader.
4. Else it return the original component with optional addition properties ( in this case myProps
5. In our example, we have calculated the loading time, for the demonstration purposes and to show that we can pass data back. What you can do using the same is left to your imaginations.
So what happens when we wrap any component in the Loading components along with a property name?
It checks if the passed property name is empty.
If its empty a loading component is returned, if data is present the original component is returned.
That wraps up the implementation of our HOC.
Now that we have understood how to write a HOC lets understand the when and whys.
In a normal case, to implement a loading component, we can check if the corresponding property ( contacts
in our example ) in respective component and render a Loading
component within the original component.
However, this will lead to redundant code. For example, we have a Feed
component controlled by contacts
and a List
component controlled by name
, we would have to check if the data is present in two different cases and render the loading components.
A generic higher order component as shown in the above example avoids this. So in case, we have to implement loading for the List
component, in the List.js
we can simply do
export default Loading("name")(List);
This is just one application of HOC, you can use it in any way you want. Basically what it does is
- Take a component as argument
- Return something — this can be anything. Literally anything. You can completely disregard the original component and render something completely new.
What you want to do is up to your imaginations. In short, HOC helps you organise your codebase in a much better way and to decrease code redundancy.
Even Redux uses HOC. The connect statement that you have come across is a HOC that does so many things with the original component.
If you see the same code is written in many places in your codebase there might be a chance to move this to a HOC and make your codebase a lot cleaner.
For more, follow me on twitter.