DEV Community

Cover image for React - Higher Order Components (HOC)
Nicolas B.
Nicolas B.

Posted on • Edited on

React - Higher Order Components (HOC)

In the ever-evolving realm of web development, mastering advanced concepts is essential for creating robust and flexible applications. In this article, we'll delve into one of these foundational React concepts: Higher-Order Components, commonly known as HOCs. 

Whether you're a seasoned developer seeking advanced techniques or a curious beginner eager to learn, we'll walk through the creation and application of HOCs step by step. Get ready to enrich your development toolkit with this powerful approach while discovering how to enhance the readability, reusability, and maintainability of your code.


What is a Higher Order Component?

Imagine that you own a pastry shop and you specialize in creating a wide variety of pastries. In your pastry shop, you have croissants, muffins, and danishes. Each pastry must have a label indicating its type and ingredients. If you were to do this for every pastry manually, it would require a significant amount of time. Instead of doing it manually, you can use a "robot" that will do it automatically for you.

This robot is a Higher-Order Component (HOC), a function that takes a component (your pastry) and returns your pastry with additional functionalities or features (in this case, a label indicating its type and ingredients).


Advantages

Higher-Order Components (HOCs) offer several significant advantages that enhance how we develop our React applications. Here are some of these advantages, accompanied by concrete examples:

  • Reusability: One major strength of HOCs is their ability to be reused in different parts of your application. Since an HOC is a function with specific logic, you can customize it to suit your needs while keeping it flexible. For instance, an authentication HOC could be adapted to handle access to different types of content. 
  • Separation of Concerns: Instead of cluttering a component with multiple distinct logics, HOCs allow for the separation of these responsibilities into distinct components. You can easily envision creating a separate HOC for each logic, making your components clearer and better organized. 
  • Code Modularity: HOCs add a modular layer to your code. You can add or remove an HOC without affecting the functionality of the underlying component, making maintenance and adaptation of your application easier. In essence, HOCs nest without altering overall stability. 
  • Facilitation of Unit Testing: Due to their isolated nature, HOCs simplify unit testing. You can test the specific logic of an HOC without the complexity of other parts of the application.

By combining these advantages, you'll be able to create more flexible and maintainable applications while minimizing code duplication.


Practical Case

The problem

Let's take a concrete example to illustrate the relevance of Higher-Order Components. Suppose we're developing an application with an authentication system. In this application, different parts of the interface require authentication:

  • Home Page: This page doesn't require authentication.
  • List of Books: This list can be viewed without authentication.
  • Top Books: This section is reserved for authenticated users.
  • User Ratings: Similarly, only logged-in users can view the ratings.

Imagine we have a component that imports all the others:

export const App = () => {
  return (
    <div>
      <Home />
      <BooksList />
      <TopBook />
      <UsersRating />
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

Now, let's consider a component for each part:

export const Home = () => {
  return (
    <div>
      <h1>Hey !</h1>
      <p>This is a welcome message !</p>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode
export const BooksList = () => {
  return (
    <div>
      <p>Books list</p>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode
export const TopBook = () => {
  const isConnected = false

  if(!isConnected) {
    return (
      <p>You don't have access !</p>
    )
  }

  return (
    <div>
      <p>Top Book</p>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode
export const UsersRating = () => {
  const isConnected = false

  if(!isConnected) {
    return (
      <p>You don't have access !</p>
    )
  }

  return (
    <div>
      <p>UsersRating</p>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

We notice that the two components with the restriction logic repeat the same code. While this isn't a big issue with only two components, imagine having 10 components - that's a lot of code repetition. Given this scenario, it's important to find a solution that handles conditional content display based on authentication status.

This is where Higher-Order Components (HOCs) come into play.

Solution : Higher Order Components (HOCs)

To address this issue of code repetition in multiple places, let's isolate the authentication logic in an HOC called withAuthentication:

export const withAuthentication = (Component) => {
  const isConnected = false

  if (!isConnected) {
    return <p>You don't have access !</p>
  }

  return (props) => <Component {...props} />
}
Enter fullscreen mode Exit fullscreen mode

Next, we'll apply this HOC to the components that require access restriction, like this:

export const TopBook = withAuthentication(() => {
  return (
    <div>
      <p>Top Book</p>
    </div>
  )
})
Enter fullscreen mode Exit fullscreen mode
export const UsersRating = withAuthentication(() => {
  return (
    <div>
      <p>UsersRating</p>
    </div>
  )
})
Enter fullscreen mode Exit fullscreen mode

Assuming you retrieve isConnected from either props or context, you now have isolated and reusable logic.


Going further

We can go further with HOCs. Let's imagine now that we want to do some layout work with a profile view:

export const Profile = () => {
  // This is the beta version of the Profile

  return (
    <div>
      <p>Beta Profile</p>
      <h1>Nicolas BROUARD</h1>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

We have our Profile view and we want to add a "Beta" banner to indicate that this is indeed the Beta version of the profile. We can also use an HOC:

export const withBetaBanner = (Component) => {
  return (props) => (
    <>
      <header className="beta-header">This is a beta version</header>
      <Component {...props} />
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

You can easily nest various HOCs if needed:

const ProtectedBetaProfile = withAuthentication(withBetaBanner(Profile))

return <ProtectedBetaProfile />;
Enter fullscreen mode Exit fullscreen mode

This allows you to isolate different rules, making unit testing easier! You can also manipulate props if necessary. HOCs are very powerful!


You can also manipulate props if necessary. HOCs are very powerful!

Conclusion

In conclusion, you now have all the tools you need to fully leverage the power of Higher-Order Components (HOCs) in your React projects.

By combining concepts such as prop forwarding, HOC composition, and using TypeScript for type safety, you can create more flexible, cleaner, and efficient components. HOCs provide a practical approach to handling cross-cutting concerns and simplifying your components, which can greatly facilitate maintenance and expansion of your applications. Keep experimenting with HOCs in your projects and don't hesitate to explore concrete examples to deepen your understanding.

Mastering the art of HOCs will give you a significant advantage in building robust and scalable React applications. So, dive in, apply this knowledge, and transform your components into flexible and powerful building blocks for your future React creations.

If you enjoyed this tutorial, please consider following me for more helpful content. Your support is greatly appreciated! Thank you!

Top comments (18)

Collapse
 
nickap profile image
nickap

HOCs are super helpful!

Seems you forgot to remove:

'if (!isConnected) {

return

You don't have access !



}'

from your components after implementing hocs
Collapse
 
brdnicolas profile image
Nicolas B.

Thanks for your feedback,
This is my very first article and I left a small typo thanks!

Collapse
 
nickap profile image
nickap

Congrats for your 1st article Nick!

Thread Thread
 
brdnicolas profile image
Nicolas B.

Thank's a lot ! :)

Collapse
 
manojadams profile image
Manoj

Nice example.

The above example can be implemented using a common wrapper component as well.

It will be super helpful if we can see some more examples for HOC where
using HOC is the only way and cannot be implemented using wrapper components.

Collapse
 
davboy profile image
Daithi O’Baoill

Nice article, thank you.

Collapse
 
alvesjessica profile image
Jessica Alves

Great explanation! 👏🏼

Collapse
 
kurealnum profile image
Oscar

Nice article. I didn't even know HOCs existed until now!

Collapse
 
scorcism profile image
Abhishek Pathak

it's great

Collapse
 
j0nathansf profile image
Jonathan

That was a great article, I was looking for a introduction to React's Higher-Order Components. It will be helpful

Collapse
 
brdnicolas profile image
Nicolas B.

Hi ! Thank's bro !

Collapse
 
luka_brouard_7c90194e8fd1 profile image
Luka Brouard

congratulations for yur first article, he is very nice, quadruple monstre,
spike down

Collapse
 
anasjmirza profile image
Muhammad Anas

easy explanation, Thanks

Collapse
 
pouriarezaeii profile image
Pouria Rezaei • Edited

Congrats on your first article. It's straightforward.

As Nickap mentioned there are some small typos.
After adding HOC you should remove these lines from your components:

if (!isConnected) {
     return <p>You don't have access !</p>
}
Enter fullscreen mode Exit fullscreen mode

Additionally the HOC needs a slightly change:

return (props) => {
  if (!isConnected) {
    return <p>You don't have access !</p>
  }

  return <Component {...props} />
}
Enter fullscreen mode Exit fullscreen mode