App render after adding a Higher-Order Component

Understanding React.js Higher-Order Components

In this tutorial, we will approach React.js Higher-Order Components (HOCs), with the help of an easy to understand, basic example. To follow along, you will need some React.js and JavaScript knowledge, but everything is detailed in the checklist below.

Download the source code

You can follow along, and build your app from the ground up, or better yet, you can download the files used in the tutorial from here.

Before moving forward

Note that after downloading the files, to get the app running you will have to navigate to the project folder: cd my-hoc and install the dependencies by running npm install in your terminal.

What will you need – checklist

  • Basic knowledge of React.js and JavaScript (ES6 Arrow Functions). You can check out the Beginner’s Guide to React.js with examples tutorial, or the Build Web Apps with React JS and Flux course, which covers everything you need, and more. If you have a basic knowledge of React.js and want to continue your learning journey by adding more complex patterns/concepts to your tool-belt, then this article is for you! We will use an easy example of HOCs to get you familiar with the possibilities, which you can later apply to your more advanced projects.
  • Text editor of your choice. Some popular text editors are Atom, Sublime Text, Notepad++. Syntax highlighting is a plus.
  • To get started quickly, we will use create-react-app, which handles the creation of all our starter files, so we can focus on development faster. If you wish to follow along, make sure to have Node.js >= 6 on your local development machine and npm installed, as this is a requirement for the create-react-app .

What are Higher-Order Components (HOCs) ?

Basically, a Higher-Order Component (HOC) is a function that takes a component as an argument, and returns another component. The returned component is not any kind of component, it’s a component with superpowers (sadly not the kind of superpowers we all wish we had when we were kids), so to say.
It’s actually that simple! ????

Note from The React docs:

HOCs are not part of the React API, per se. They are a pattern that emerges from React’s compositional nature.

Higher-Order Components are a powerful pattern, for providing and fetching data to other components.

When can we use Higher-Order Components (HOCs) ?

Whenever we want to wrap a repeating pattern. Also, having repeating code with a lot of functionality would be difficult to maintain in larger applications.

However it’s best not to overuse them – and always check if another pattern could be more appropriate.

That being said, let’s get started!

We will begin by bootstrapping our project with create-react-app . Let’s open up our terminal window, and run:

npx create-react-app my-hoc

You can also use npm init , which is available in npm > 6

npm init react-app my-hoc

Or if you prefer Yarn

yarn create react-app my-hoc

 

This will create the my-hoc folder, with our initial project structure.

Once the installation is completed, still in our terminal, we will navigate to the project folder: cd my-hoc

And start the development server with npm start .

Note: If you are using Yarn, you can run yarn start .

A new browser page should open, but if it doesn’t, navigate to http://localhost:3000/ to see your app running.

App initial page

Our initial project structure will look like this:

App initial folder structure

Now, let’s do some cleaning. We will remove the logo and the generated boilerplate code, and also replace the starter css with our own styles.

The files that we’ll modify are App.js and App.css , which after refactor, will look like this:

App.js file:

App.css file:

We won’t do more styling for this particular example, but feel free to unleash your inner artist and add an awesome look to the application as we build our components. ????

What will we build ?

Let’s say that we have a game, and that we want some of the player information, such as the player name and player score, to be displayed in our page.
We will want the name and score to be displayed in two places, in the score panel, and in the player card.

In future articles, we will look into how to build/use an API to store our player data, as well as building a game, but for now, for the simplicity of our example, we will hard-code the data in a separate file.

In our project src folder, we will create a new file, data.js , which will store and export our playerData .

data.js file:

While we’re here, in the src folder, let’s go ahead and create another folder, components , which will hold our PlayerInfo and ScorePanel components, that will get and display the player data. Let’s give them some code!

PlayerInfo.js file:

ScorePanel.js file:

In both components, we’ve imported the playerData from our data.js file.
We’ve defined the state with some initial values, and in the componentDidMount life-cycle method we’ve set the state to the playerData values.

The componentDidMount life-cycle method is available after the component has mounted, after the HTML from render has completed its loading. It is called once in the component life-cycle, and it signals that the component and all of its sub-components have rendered properly.
This is the place where we can do anything that we want to set up in the DOM, such as API calls.

Moving forward, let’s make use our newly created components, by including them in the App.js file.

The results displayed on the screen:

Render result before adding a Higher-Order Component

And our folder structure will be:

Project file structure before Higher-Order Component (HOC)

But wait a second…let’s take a second look at our PlayerInfo and ScorePanel components.
In both of them we are getting the playerData , setting their state to the desired values, and returning something that will be rendered.

Déjà vu ? Repeating patterns ? It’s HOC Time!

As mentioned at the beginning of this article, in React, a HOC is a function that takes a component as an argument, and returns another component with superpowers.

By doing so, we can break our application into simple and reusable functions.

To put this into practice…

We will create our HOC in a new file, withPlayerData.js . The naming convention is to use with as a prefix for the HOC, to describe the returning superpower.
This makes code maintenance much easier, as well as finding bugs faster . Also, it will help the reader to understand the code logic easily.

In our withPlayerData.js file:

Again, we are importing React and our playerData.

Next, we define our withPlayerData function, which takes WrappedComponent as an argument.

Then, we have the constructor with our state, which stores the name and score of our player, the componentDidMount life-cycle method, that we will use to get our player name and score from the data.js file, and last but not least, the render method. So basically we’ve moved the repeated logic from the other two components into this one.

In the render methods return statement, we have our initial argument – the WrappedComponent .
This WrappedComponent has our props:

And it’s receiving the source components props from {...this.props} .

 

What does {...this.props} actually do.

It’s called spread attribute, and it makes the passing of props easier.
Imagine that later on, we will want to add more player data such as unlockables, skins, stats, skills, currency and so on. If you have a component that accepts a number of props, passing them down can be overwhelming and tedious when/if their number grows. Taking this into account, instead of passing props like this:

<OurComponent foo={} bar={} baz={} lorem={} ipsum={} kitty={} />

We can simply wrap them up in an object and use the spread notation to pass them to our component: <OurComponent {...props} /> , and in OurComponent , we can then use the props normally.

 i.e

Back to our withPlayerData HOC, in which we have now created a reusable provider for the player data!

Refactoring our application…

…to make use of the newly acquired superpower, Higher-Order Component.

In our ScorePanel and PlayerInfo files, we’ll first remove the playerData , and import our withPlayerData HOC, to make use of it.

ScorePanel.js file:

Next, let’s remove the constructor , state , and componentDidMount life-cycle method.

Because we have moved all the functionality to our HOC, our component only needs to render, so we can use a functional component instead of a Class component.

A functional component is just a JavaScript function which accepts an argument( props), and returns a React element. They are useful for presentational components which focus on the UI, rather than on behaviour.

So why use a functional component?!

  • Because it’s easier to read
  • Because it’s easier test
  • Because it’s less code

The resulting, refactored functional component:

And to use our HOC, we just have to export it with our component passed in as an argument:

export default withPlayerData(ScorePanel)

Finally, our ScorePanel components new look:

Nice, clean and simple.

Applying the same refactor in the PlayerInfo.js component:

The results:

App render after adding a Higher-Order Component

And that’s it! We have used a Higher-Order Component to handle our playerData logic and pass it to our other components. As our applications grow, it’s common to have components that display the same data, but in a different way. That being said, as you can see, Higher-Order Components are useful.

Some HOCs Cons

  • Reusability – can be as much of a con, as it can be a pro. Placing a lot of reusable code into a Higher-Order Component, can involve passing a lot of props, thus leading to collisions.
  • Refs aren’t passed through.
  • Static methods must be copied over

Where to go from here

If you want to strengthen your understanding beyond this example (which is highly recommended), and don’t have any ideas on what to build next, try making a Higher-Order Component that fetches data from an API, or one that saves/loads a components state to/from local storage. Or how about one that wraps the passed in component in a container with an awesome style ?

Conclusion and Comments

Did you find the examples illustrated in this article too easy? Too complex? Just right? Have something in mind that you would like me to write about? Did you build a fun project using the concepts learned?
Let me know in the comments section below.

In the meantime, Happy Coding! ????

Published by

Eugen-Calin Suciu

Calin is a passionate Frontend developer, working for a company that provides Saas. He's also a freelancer who loves to teach coding, write tutorials, and do pro bono work.

Share this article

Leave a Reply

avatar
  Subscribe  
Notify of