Build React App Faster by Writing your Own Higher-Order Components

March 04, 2019Benoît de Malet5 min read

thumbnail

Now that hooks have officially been released in React 16.8 and that everybody is trying to convince you to rewrite all your React projects using nothing but hooks, let's see if there is still something to achieve using Higher-Order Components. (Spoiler alert: the answer is "yes")

In this article, we will see how you could avoid code duplication by learning to write your own Higher-Order Components.

We assume that you already are familiar with React and know how to build a basic app using React.

What exactly is a Higher-Order Components (HOC) ?

To quote the React documentation:

"Concretely, a higher-order component is a function that takes a component and returns a new component."

HOC_base

So basically, it can be any function that takes a component and returns something based on that component. In most cases, the HOC will inject logical behaviour to our component, allowing us to share the same logic across many components in our app and to avoid code duplication.

Why would I need this ?

Let's say that we want to build a very basic app to display data from the wonderful PokéAPI.

2usdnq

There are two different views:

  • One that displays a list of pokémons.
  • One that displays some specific data for each pokémon.

The component architecture is:

Files

The design.js files contain the design components, and the index.js files contain the containers that will handle all the logic.

For both views, the data is asynchronously fetched from the API with a fetchPokemon function and a fetchPokemons function.

Let's have a look at the two index files written as standard React components and see if some code is shared between the two.

HOC_comparaison

As we can see, most of the code we have in the two containers is basically the same.

The only differences are:

  • The name of the data field passed to the design component (pokemon / pokemons).
  • The function called to fetch the specific data (fetchPokemon / fetchPokemons).

What if we could find a way to generate the exact same logic while inserting these two parameters?

Well... That's exactly something we can achieve by writing a HOC!

Writing a withFetch HOC

Let's start by writing the skeleton of what is going to be our HOC function:

HOC_func_v1

If you are not familiar with this double arrow function pattern, don't panic! It's easier to understand than it seems:

  • withFetch is a function that returns another function.
  • The returned function takes a BaseComponent (a React Component) and returns a whole new component that will contain our BaseComponent. (Strictly speaking, this second function is our HOC).

But... Why would we need this first function if the second one already is a HOC?

Excellent question! That will allow us to add parameters to our HOC later.

Now, you may have noticed that our HOC does absolutely nothing so far. So, what we will do now is taking the logic we had in our index.js files and adapting it to work with dataName and fetchFunction as parameters.

HOC_func_v2

And that's it!

What is happening here is:

  • Whatever your fetchFunction is, it is called when the component is mounted.
  • The result is set in a field named dataName.
  • A loader is displayed while the data fetching is running.
  • When the data fetching is over, the BaseComponent is rendered with the fetched data as a prop.

Now, both index.js files can be rewritten:

HOC_index1

And this HOC could be used for any new component that has to fetch data from an api.

If you want to go further with this specific example, this withFetch HOC could be improved in many ways. It could:

  • Fetch data from multiple fetch functions.
  • Display an error message when an error is caught in the fetching process.
  • Provide a "retry" button when the fetching fails.
  • ...

If you feel like trying something a bit harder, you could write:

  • withPagination: a HOC that will handle all the logic required to display a paginated list of items.
  • withAnalytics: a HOC that will handle analytics.
  • withPassword: a HOC that will prompt for a password before rendering a component.
  • withWhateverYouMayNeed: well... I think you get the idea!

Conclusion

By writing our own HOC, we were able to decompose our components and to isolate a specific behaviour (the data fetching) that we can now use anywhere we need to. This allows us to avoid writing the same code again and again and to focus on the specific features we need for our app.

The Higher-Order Component pattern is only one into many. We could have accomplished something similar by using render props or hooks. And no, I don't believe that HOC is a better way than the others. As a matter of fact, I encourage you to try writing the same kind of fetching helpers with other patterns to see what fits your needs the most.

Regardless of the pattern you choose, the true lesson to learn here is that you should always try to write the logic you need as reusable elements. The smaller the elements the easier it will be for you to use them.

Happy coding!

Benoît de Malet

Benoît de Malet

Web Developer at Theodo