top

Introduction To Higher Order Components (HOC) In React

This tutorial is intended to give you step by step 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 are already 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 beginners understand higher order components in React better.Let’s begin with a quick introduction to Reacts higher order components: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 functionsA 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 that 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 an argument.Let’s build a HOC and learn more as we go.Higher order component in ReactLet’s look at some code straight away.const reverse = (PassedComponent) =>   ({ children, ...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. The 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 that happen with a HOC are:Takes a component as an argumentReturn somethingLet’s have a look at a more practical and complex use case.In all the apps that 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. 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. This request will be created 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}`,           email: user.email,           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 React, { 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 React, { 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 contactsNow 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 returns 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.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 it is 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 use React higher order components. Let’s 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) is 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 doexport default Loading("name")(List);This is just one application of HOC, you can use it in any way you wish. Basically what it does isTake a component as an argumentReturn something — this can be anything. You can completely disregard the original component and render something completely new.In short, HOC helps you organize your codebase in a much better way and decreases 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.
Rated 4.0/5 based on 45 customer reviews
Normal Mode Dark Mode

Introduction To Higher Order Components (HOC) In React

Sooraj Chandran
Blog
08th Jun, 2018
Introduction To Higher Order Components (HOC) In React

This tutorial is intended to give you step by step 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 are already 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 beginners understand higher order components in React better.

Let’s begin with a quick introduction to Reacts higher order components:

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 that 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 an 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) =>
  ({ children, ...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. The 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 that happen with a HOC are:

  1. Takes a component as an argument
  2. Return something


Let’s have a look at a more practical and complex use case.

In all the apps that 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

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. This request will be created 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}`,
          email: user.email,
          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 React, { 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 React, { 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.

  1. For ease of understanding assume component takes another component ( in our case Feed component ) along with a property contacts
  2. Now the Loading component checks of the loadingProp ( in our case contacts)are empty — The function isEmpty does this.
  3. 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 returns 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.

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 it is 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 use React higher order components. Let’s 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) is 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 wish. Basically what it does is

  1. Take a component as an argument
  2. Return something — this can be anything. You can completely disregard the original component and render something completely new.

In short, HOC helps you organize your codebase in a much better way and decreases 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.

Sooraj

Sooraj Chandran

Blog author

Software Engineer, Javascript Fanatic, UI/UX, Open source contributor.

Leave a Reply

Your email address will not be published. Required fields are marked *

SUBSCRIBE OUR BLOG

Follow Us On

Share on

other Blogs

20% Discount