Simply put, Higher Order Component(HOC) is a function that takes in a component and returns a new component.
When do we need a Higher Order Component?
While developing React applications, we might develop components that are quite similar to each other with minute differences.
In most cases, developing similar components might not be an issue but, while developing larger applications we need to keep our code DRY, therefore, we want an abstraction that allows us to define this logic in a single place and share it across components.
HOC allows us to create that abstraction.
Example of a HOC:
Consider the following components having similar functionality
The following component displays the list of articles:
class ArticlesList extends React.Component{
constructor(props){
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
articles : API.getArticles();
}
}
componentDidMount() {
//Listen to changes made in the API
API.addChangeListener(this.handleChange);
}
componentWillUnmount() {
// Clean up listener
API.removeChangeListener(this.handleChange);
}
handleChange() {
// Update the articles variable whenever the API changes
this.setState({
articles: DataSource.getArticles()
});
}
render(){
return(
<div>
{this.state.articles.map((article)=>(
<ArticleData article={article} key={article.id}/>
))}
</div>
)
}
}
The following component displays the list of users:
class UsersList extends React.Component{
constructor(props){
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
users : API.getUsers();
}
}
componentDidMount() {
//Listen to changes made in the API
API.addChangeListener(this.handleChange);
}
componentWillUnmount() {
// Clean up listener
API.removeChangeListener(this.handleChange);
}
handleChange() {
// Update the users variable whenever the API changes
this.setState({
users: DataSource.getUsers()
});
}
render(){
return(
<div>
{this.state.users.map((user)=>(
<UserData user={user} key={user.id}/>
))}
</div>
)
}
}
Notice the above components, both have similar functionality but, they are calling different methods to an API endpoint.
Let’s create a Higher Order Component to create an abstraction:
class UsersList extends React.Component{
constructor(props){
super(props);
this.handleChange = this.handleChange.bind(this);
this.state = {
users : API.getUsers();
}
}
componentDidMount() {
//Listen to changes made in the API
API.addChangeListener(this.handleChange);
}
componentWillUnmount() {
// Clean up listener
API.removeChangeListener(this.handleChange);
}
handleChange() {
// Update the users variable whenever the API changes
this.setState({
users: DataSource.getUsers()
});
}
render(){
return(
<div>
{this.state.users.map((user)=>(
<UserData user={user} key={user.id}/>
))}
</div>
)
}
}
We know HOC is a function that takes in a component and returns a component.
In the code above, we have created a function called HOC which returns a component and performs a functionality that can be shared across both ArticlesList component and UsersList Component.
The second parameter in the HOC function is the function that calls the method on the API endpoint.
We have reduced the duplicated code of the componentDidUpdate and componentDidMount functions.
Using the concept of Higher Order Components, we can now render the ArticlesList and UsersList component in the following way:
const UsersListWithHOC = HOC(UsersList, (API) => API.getUsers());
const ArticlesListWithHOC = HOC(ArticlesList, (API)=> API.getArticles());