Home

Introduction to higher order components (HOC) in React

You can find the entire working code here. And a live demo here.

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 * y
multiply(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.

const reverse = (PassedComponent) =>
  ({ childrenundefined ...props }) =>
    <PassedComponent {...props}>
      {children.split("").reverse().join("")}
    </PassedComponent>

const name = (props) => <span>{props.children}</span>
const reversedName = reverse(name)
<reversedName>Hello</reversedName>
//=> <span>olleH</span>

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.

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.

componentDidMount() {
    fetch("https://api.randomuser.me/?results=50")
      .then(response => response.json())
      .then(parsedResponse =>
        parsedResponse.results.map(user => ({
          name: `${user.name.first} ${user.name.last}`undefined
          email: user.emailundefined
          thumbnail: user.picture.thumbnail
        }))
      )
      .then(contacts => this.setState({ contacts }));
  }

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.

import Reactundefined { Component } from "react";
import FeedItem from "./FeedItem";
import Loading from "./HOC/Loading";

import FeedStyle from "./Feed.css";

class Feed extends Component {
  render() {
    return (
      <div className="justify-content-center align-items-center">
        <FeedItem contacts={this.props.contacts} />
      </div>
    );
  }
}

export default Loading("contacts")(Feed);

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.

import Reactundefined { Component } from "react";

const isEmpty = prop =>
  prop === null ||
  prop === undefined ||
  (prop.hasOwnProperty("length") && prop.length === 0) ||
  (prop.constructor === Object && Object.keys(prop).length === 0);

const Loading = loadingProp => WrappedComponent => {
  return class LoadingHOC extends Component {
    componentDidMount() {
      this.startTimer = Date.now();
    }

    componentWillUpdate(nextProps) {
      if (!isEmpty(nextProps[loadingProp])) {
        this.endTimer = Date.now();
      }
    }

    render() {
      const myProps = {
        loadingTime: ((this.endTimer - this.startTimer) / 1000).toFixed(2)
      };

      return isEmpty(this.props[loadingProp]) ? (
        <div className="loader" />
      ) : (
        <WrappedComponent {...this.props} {...myProps} />
      );
    }
  };
};

export default Loading;

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 property contacts
  • Now the Loading component checks of the loadingProp ( in our case contacts)are empty — The function isEmpty 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.

Else it return the original component with optional addition properties ( in this case myProps

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.

...