DEV Community

Brian Maina
Brian Maina

Posted on

Higher Order Components.

Have you ever used React and felt compelled to duplicate the same logic across numerous components? I'm sure you're wondering if there's a method to reuse logic across multiple components in React without rewriting it. Yes, there is! Higher-Order Components (HOCs). HOCs offer an advanced approach to dealing with such cross-cutting concerns.
In this tutorial, you'll explore HOCs in-depth, why there’s a need for HOCs, when to use the pattern, what's a HOC and finally, create a simple React app using HOCs.

Why’s there a need for a HOC?

Imagine a client approached you, then asked you to create an App with a button indicating the number of times it’s clicked. You create a component called ClickCounter, where you store the button and its counter functionality. Export, then import and render it in the App component.

1.png
After some time, the client comes back and asks you to add a heading indicating the number of times it’s hovered over. Basically a ClickCounter with click functionality replaced by hover functionality. You create a new component called HoverCounter which stores the heading and counter functionality. Export, then import and render it in the App component under ClickCounter.

2.png
Again, the client comes back and asks you to add an input that counts the number of keypresses in the project. For Example A key up in an input element to increment a counter value and display it. You can of course implement it the same way you implemented the counter in ClickCounter and HoverCounter. But realize you are duplicating code and not really reusing the counter functionality. So if 10 different components needed the counter functionality you would write the same code over and over again.
So how can you really reuse the counter functionality?
The immediate thought is to lift state from the parent component and pass it down the handler as a prop. Define the counter functionality in App component, provide the state and the handler as props to ClickCounter and HoverCounter. Since you only have two components, it would work. But imagine a scenario where the counter components are scattered across the React App. Lifting the state would definitely not be the correct solution. So there’s a need to share common functionality among components without repeating code. That’s where the concept of HOCs comes in.

So when do you really use the HOC pattern?

Basically HOCs allow you to share common functionality between components.

What’s a HOC?

Basically, a HOC is a pattern where a function takes a component as an argument and returns a new component.

3.png
A HOC adds additional data or functionality to the component. The new component can be referred to an EnhancedComponent.

4.png
From a non-technical point of view

5.png

withSuit is the function that will enhance TonyStark and return IronMan which is the EnhancedComponent.
From React's point of view we have function which accepts OriginalComponent adds functionality and returns the EnhancedComponent.
Consider implementing a basic HOC then implement it with the counter example-
Create a new file called withCounter.js within the components folder.

Consider this example-

6.png
In the above example, the UpdatedComponent is a function that takes a component called OriginalComponent as an argument. You have created a new component called NewComponent which returns the OriginalComponent with a name prop from its render function. While this actually adds no functionality, it depicts the common pattern that every HOC will follow.

Creating a simple React app using HOCs.

Apply the HOC pattern to the ClickCounter and HoverCounter. In ClickCounter you will import UpdatedComponent from withCounter while exporting it will call the UpdatedComponent function passing in the ClickCounter component. You’ll do the same for HoverCounter. Instead of exporting the ClickCounter or HoverCounter component you export the UpdatedComponent. The HOC in addition to being the ClickCounter or HoverCounter.
To modify your HOC so as to allow the counter functionality to be shared among components. You will cut the constructorand incrementCount function from ClickCounter into the HOC. Since it’s the common functionality we want to share, remove the same code from HoverCounter.
You need to pass down the state and incrementCount method as props so that the OriginalComponent can make use of that functionality.

7.png

In both ClickCounter and HoverCounter you will destructure count and incrementCount from this.props. If you look at the project, it functions as perfectly but the difference now is that you are reusing code instead of duplicating it.

8.png

9.png

Now, you can change the naming convention. The component and functions you have used are different from what you typically see. So change them. The function and file name is usually the same, it indicates the functionality being added to the components. The OriginalComponent is usually referred to as the WrappedComponent. The NewComponent is usually the same as the function name, but in Pascal case.

10.png

You’ll make the same changes to the naming convention while importing and exporting the HOC in the ClickCounter and HoverCounter.

11.png

12.png

Before winding up consider these two things:

  • Passing down the props. In App component you will pass a name prop in the ClickCounter component.

13.png

Render the name prop in ClickCounter.

14.png

If you go to the browser the name value is not displayed. This is a common mistake when starting off with HOCs. The problem here is that when you specified props on the ClickCounter component, the props are passed down to the HOC and not ClickCounter. If you log out the name from in the HOC in the render method. You can see you do have the name prop for ClickCounter and undefined for HoverCounter.

15.png

To fix this issue you need to pass down the remaining props to the WrappedComponent using the spread operator. Basically the HOC adds two props to the App component then passes down the remaining specified props.

16.png

  • Passing parameters to the HOC function. In the HOC instead of incrementing the value by 1. You would want to increment it by different numbers for both Counter components. You can do that by passing a parameter to the HOC function. First WrappedComponent and second incrementNumber. You will now increment the incrementCount by the incrementNumber parameter.

with-Counter.png

In ClickCounter you will add a second argument 5 and HoverCounter You will add 10.

click-Counter.png

Conclusion

Congratulations! 🚀 You’ve reused common functionality within components in your application. Following the methodology in this tutorial can reduce errors caused by duplicating code. I hope you enjoyed this tutorial!

Top comments (1)

Collapse
 
kadeesterline profile image
Kade Esterline

I really like the const IronMan = withSuit(TonyStark); analogy you made