Sai Teja
LightMap

LightMap

Higher-Order Components in React: What, Why, Where?

Higher-Order Components in React: What, Why, Where?

Let us understand higher-order components in React!!

Sai Teja
·Jan 17, 2022·

6 min read

Subscribe to my newsletter and never miss my upcoming articles

Play this article

Table of contents

  • Higher-Order Functions
  • Higher-Order Components
  • Conclusion

React as we all know is a javascript framework built by Facebook for frontend development. In this blog though we will see one particular concept or pattern in React known as Higher-Order Components (HOC).

Now, though we can directly jump into HOCs but let us explore Higher-Order Functions (HOFs) before getting into it. Basically, HOCs in React was inspired by Higher-Order Functions in JavaScript.

Higher-Order Functions

We know that in Javascript, functions play a vital role and are treated as values (thus are referred to as first-class citizens ).

Due to this, a function can be assigned to a variable, it can be passed to another function and a function can also be returned from another function. This can be astonishing for people working with C/C++.

Alright, so what is a higher-order function?

Higher-Order Function: It is basically a function that takes a function as an argument and/or returns a function.

Let us understand with an example!

const success = function() {
    console.log("Success");
}

const task = function (fn) {
    fn();
}

task(success);
// Success

In the above example, we can see that the function task takes a function as an argument and calls it inside it. Thus the task is a higher-order function.

const success = function() {
    return function() {
        console.log("Success");
    }
}

const task = success();

task();
// Success

In the above program, the function success returns a function that logs Success. We call this function and assign the returned function to task then we call task to execute the returned function.

Here the function success is a higher-order function as it returns a function.

All our ES6 methods like map, filter, reduce etc are higher order functions.

Now we can go on talking a lot about higher-order functions but let us get into the main topic Higher-Order components.

Higher-Order Components

Higher-Order Component is really a very powerful pattern in React and can help reuse a lot of code. So, let us first see what exactly is a higher-order component?

What?

According to React Docs, a higher-order component is a function that takes a component and returns a new component.

We know that components in React take in props and returns UI but a higher-order component is a component that transforms one component into another component.

I hope you understood why I explained higher-order functions before this, they are pretty similar.

If you are a react developer then you might have observed that we use a lot of similar code on different pages, for example, getting logged in user data etc. This can be solved by using higher-order components.

Let us see a few examples now and that will probably make it clear.

Let us start with a simple HOC wherein the HOC doesn't add any additional functionality to the passed component.

//HOC
import React from 'react';

export const HOC = (PassedComponent) => () => {
  return <PassedComponent />;
};

We can clearly see here that the function HOC takes in a component PassedComponent and returns a component which renders the PassedComponent. Though it doesn't transform it, it is still a higher-order component.

Now let us see a little more complex higher-order component.

Say we need a component that has an h1 and a button and on every button click, the text should toggle between "Yes" and "No"

Let us see how can we use HOC for this use case.

ToggleHOC.js

import React, { useState } from 'react';

export const ToggleHOC = (PassedComponent) => () => {
  const [toggled, setToggled] = useState(true);
  const toggle = () => {
    setToggled(!toggled);
  };
  return <PassedComponent toggled={toggled} toggle={toggle} />;
};

Component.js

import React from 'react';
import { ToggleHOC } from './ToggleHOC';

const Component = ({ toggled, toggle }) => {
  return (
    <div>
      <h1>{toggled ? 'Yes' : 'No'}</h1>
      <button onClick={toggle}>Toggle</button>
    </div>
  );
};

export default ToggleHOC(Component);

And now you can use this component as follow

import Component from './Component';

<Component />

What's happening in the above example?

In the ToggleHOC.js

-> We create a higher-order component named ToggleHOC.
-> ToggleHOC has a toggled state and has a toggle function that toggles the state between true and false.
-> ToggleHOC returns the passed component but also passes the toggled state and toggle function into the passed component and then returns it.

In Component.js

-> Here we import ToggleHOC.
-> We create a Component that has an h1 with text being "Yes" if the toggled prop is true and "No" if the toggled prop is false.
-> We have a button whose onClick is set to toggle function passed from the HOC.
-> Then we export this component as export default ToggleHOC(Component) so that we can use the transformed component returned by the HOC.

As shown in the third snippet, now you can use this component as usual anywhere and it will have the toggle functionality.

Why

Hmm ok, that is fine, you are passing a component and you are getting back a component with some additional features, but why? why can't you implement that functionality there itself instead of passing it into a HOC?

Let us answer this.

Now, take the toggler example above, say that you have added state and all the functionality inside the component itself.

But what if you need similar toggle functionality somewhere else, say you have a button that will toggle between open and close when clicked?

Yes, you will have to write the toggled state, toggle function again, instead you can just do the following.

Componet2.js

import React from 'react';
import { ToggleHOC } from './ToggleHOC';

const Component2 = ({ toggled, toggle }) => {
  return (
    <div>
      <button onClick={toggle}>{toggled ? 'Open' : 'Close'}</button>
    </div>
  );
};

export default ToggleHOC(Component2);

See, we reused so much code and we can do this as many times as required. I hope you are getting how powerful HOCs can be in React in terms of reusability.

I hope you got some clarity on this, if not, do write in comments so that I can clear it for you.

Where

By now you might have realised how powerful can the HOC pattern be. Now let us look into some real-world use cases and how can we reuse a lot of code using HOCs.

  1. Authorization : On all the pages which need authorization we tend to have some common code which check for user info and if it is not present, we redirect it to auth page. We can write a higher order component to handle this for all the other components.

  2. Toggling And Similar Functionalities : We already saw how can we implement and use HOCs for toggling functionality and even similar functionality where we repeat a similar kind of state in a lot of components.

  3. Styling: In case you are using one style at a lot of places, then you can just use a HOC which returns back the same component with the style you were using. This way you can reduce a lot of code.

  4. Conditional Rendering: In a lot of components we see that we render conditionally depending upon a variable or a states value. We can use HOC for this as well and get rid of that code in all those components.

There can be a lot more use-cases as well.

HOCs are used in a lot of popular libraries as well like Redux and MUI.

Conclusion

So, those were some basics on Higher order components. After the advent of Hooks, HOCs usage has decreased but it is still relevant in a lot of cases where you have a lot of components with same behavior.

I understand it can be confusing at first glance but as you use it, you will get good at it. Put in any doubts in comments and I will get back to you for sure.

Follow me on Twitter @saai_tejaa.

 
Share this