Higher-Order Components (HOC) — Real world example
In case you want to learn about Higher-Order Components with a real world example, you’ve came to the right place!
I’m going to start introducing myself, my name is Luis Serrano, I’m a Software Engineer at Hole19 and this is my first dev article!
In case you’r a golfer or even if you aren’t, you should try our app/website 😎.
We are a community of 1.3 Million golfers around the world that use the app to Book Tee Times, to discover great courses and to gain a better understanding of their game and connecting with their golf friends!
A while ago our team had to redesign our booking page, where the user can filter courses by holes, time, extras, etc (golf stuff 😄) with a custom dropdown.
For this problem, I’ve found that this ‘little’ component will be used with different filters, but always with the same functionality. Only the content of each dropdown would be different.
So I wondered, do I really need to make each filter component duplicate the dropdown functionality? I’ll copy/paste a lot of code! 😔
If you want to share the same functionality across different components, HOC for the rescue! With this pattern, I can reuse the dropdown functionality when I want to create a new filter that should be inside the dropdown.
Since I’ve never implemented anything with this Higher-Order Component pattern, I thought this was the right time to learn and implement it.
This article assumes ES6 and React knowledge.
Hint: You have a bonus at the end of the article 😉.
A higher-order component (HOC) is an advanced technique in React for reusing component logic.
A higher-order component is a function that takes a component and returns a new component.
Basically a Higher-Order Component is a function that you can ‘decorate’ some functionality to a new component.
This function receives a component as an argument and returns a new one with specific functionality, rendering the component you just passed as an argument. Pretty simple, I’ll show you how in a second.
In our case, the HOC will give the component the ability to Toggle (open, close the dropdown), to select each item inside the dropdown and call some handler we pass through props and close the dropdown.
These filters must show a label and the value that is selected on each one and this will be the same for everyone. When the user click on any filter, it should open the dropdown with the options of the filter. But there is a catch, the options of each filter can be different. I can have a input range, a list of options, a list of options with checkboxes and a button to apply the changes, etc. And this is the dynamic part.
The content of each filter can be very different, you can see below or live at Hole19 Tee Times.
The things that I just need to do are the callbacks for those filters to change state and fetch some information with new values, and the component for each filter, but the dropdown functionality need to be made only in one place.
And this use case, it’s perfect for using the Higher-Order Component pattern because I need to share this functionality across all filters that need to be inside the dropdown!
To start, let’s implement a simple and basic HOC. As you can see, withDropdown function receives WrappedComponent, returns a new React Component and render the WrappedComponent.
To implement the functionality of a dropdown, we must add some functions to open/close the dropdown and the callback for each click event inside the dropdown.
Finishing this HOC, I still have work to do. As you’ll see, the HTML that I need to build for the filter will be the same for all. So let’s make a stateless component to build this filter.
Just an important note in this component, sometimes when the user select an item or play with whatever the dropdown have, we don’t want to hide the dropdown! For that, we need to override that call to the onSelect method, which will hide the dropdown and call some handler we passed through props.
To override the call to the onSelect method, I’ve used React.cloneElement function, witch receives a component in the first argument and the second argument is where you will add your new props.
props.children will be the dynamic side. It’s the content of each dropdown that can be different. If in any filter, the dropdown cannot disappear if the user click inside or drag, the default behavior must be override.
Just a note, Optional() is our abstraction to the usual ternary operator. If you want to render something, checking if some state or props property is true or false, without rendering if the condition doesn’t meet you could do something like this instead:
props.showDropdown ? <Example1 /> : null
In your main React Component, where you will have your handlers, main state, etc, you have to import those components. Let’s get to it:
handleFilterState is the function to change the state and trigger a fetch call for example.
Time and Price components are the ones for the dropdown to render. As you can see, our Price component must have a different onSelect method, instead of passing through the Dropdown component, we pass directly through Price component.
Time component could be something like this:
And for the bonus, here it is: A functional and working example of the dropdown!
If you want to learn more about Higher Order Components, check it out these awesome articles and videos.
You have endless possibilities to use this pattern.
If you see that a lot of components just fetch some data from an endpoint and render some content, you could use a HOC for that and abstract the fetch stuff to there. There are a lot of use cases for this pattern!
And thats it! Hope you like it and it would be great to get your feedback too :)