A practical example to understand higher order components in React JS.

As you build React applications, you will run into situations where you want to share the same functionality across multiple components. Let’s see an example. Say you have three separate JSON files in your application which contains different data that will be loaded in your application in three different components. You want to give your users the ability to get the data loaded from these files in a single search. You could implement a search feature in all three of the components and then return the aggregate output in a fourth component. The duplication will not be an issue in smaller applications, but as your application grows and more components need this functionality, the constant duplication will be cumbersome and prone to problems. A better way forward is to create a higher-order component to handle the search functionality. With it, you can wrap the other components individually in your higher-order component. Let’s start with a basic example. Here’s a higher-order component that prints a wrapped component and adds a header to it.

const HOC = (WC) => (val) => {
  return (
    /////////////////////////////
    function (props) {
      return (
        <div>
          <WC>
            {props.children}
            <h2>{val}</h2>
          </WC>
        </div>
      );
    }
    /////////////////////////////
  );
};
export default HOC;

This HOC takes another component as input and returns another functional component that will in turn render the input component. the second parameter val is utilised inside the returned functional component. The returned is not named and accepts a props for accessing children property of props. So our wrapper must similar method signature to render all the children in same manner. Check this wrapper component that applies some functionality over children defined inside its tags.

import HOC from "./HOC";

function WrappedComponent(props) {
  return (
    <div>
      <h1>I am Wrapped Component</h1>
      {props.children}
    </div>
  );
}
export default HOC(WrappedComponent)("Inside HOC");

And finally, I have written some child components in App.js file. Also I have wrapped the HOC over wrapper component and rendered the output inside App.js

import WrappedComponent from "./WrappedComponent";

function Child1() {
  return (
    <div>
      <h1>I am Child 1</h1>
    </div>
  );
}
function Child2() {
  return (
    <div>
      <h1>I am Child 2</h1>
    </div>
  );
}

function Child3() {
  return (
    <div>
      <h1>I am Child 3</h1>
    </div>
  );
}

export default function App() {
  return (
    <div className="App">
      <WrappedComponent>
        <Child1 />
        <Child2 />
        <Child3 />
      </WrappedComponent>
    </div>
  );
}

I have attached the codesandbox for users to checkout the actual code.

Now using the concept of HOC over a practical problem. I have json file containing user data in an array. Each element has three properties, name, age and zone. Using HOC I have implemented the feature of extracting user details using single keyword from name, age or zone.

First lets make the Userdetails component.

export default function UserDetails(props) {
  return (
    <div>
      <h3>{props.Name}</h3>
      <h3>{props.Age}</h3>
      <h3>{props.Zone}</h3>
    </div>
  );
}

Now lets make the parent component that will print out all the user details. The UserList component takes three props values as inputs, one is list of user details, second is search keyword and the third is a variable value provided HOC wrapper function which we define in a while.

import UserDetails from "./UserDetails";
import Search from "./Search";

const Locations = (props) => {
  const { userData, search } = props;

  return (
    <div>
      <ul className="Locations">
        {userData
          .filter(
            (user) =>
              `${user.Name} ${user.Age} ${user.Zone}`
                .toUpperCase()
                .indexOf(search.toUpperCase()) >= 0
          )
          .map((user) => (
            <li key={user.Name}>
              <UserDetails {...user} />
            </li>
          ))}
      </ul>
    </div>
  );
};
const HOC = Search(Locations);
export default HOC;

I have combined all the property values and converted them to uppercase and then filtered the results using the search keyword from props. The wrapper HOC provides the search keyword as well.

Now lets check the HOC wrapper code.

import React, { Component } from 'react'
import users from "../Data/Data.json";

const Search = (WrappedComponent) => {
  return class extends Component {
    state = {
      searchTerm: ''
    }
    handleSearch = event => {
      this.setState({ searchTerm: event.target.value })
    }

    render() {
      return (
        <div>
          <div>
            <input 
            onChange={this.handleSearch} 
            value={this.state.searchTerm} 
            type="text" />
          </div>
          <WrappedComponent 
          search={this.state.searchTerm} 
          userData={users.data}
          />
        </div>
      )
    }
  }

}
export default Search;

The Search component (or, a HOC wrapper component) accepts two values, a wrapped component(in our case UserList) and a string literal. It returns another class based component. The returned component has a search input bar and renders the wrapped component. Also it provides the user data list, the search keyword and a string literal as props value which we saw in the above code(UserList).

And Finally, we have our App component.

import "./styles.css";
import UserList from './Components/UserList';
import Search from './Components/Search';

export default function App() {
 const HOC = Search(UserList,'Inside HOC')('Inside Users');

  return (
    <div className="App">
      <h1>User Data</h1>
      <hr style={{'width':'100%','textAlign':'left','marginLeft':"0"}}/>
        <HOC />
    </div>
  );
}

As you can see in line 6 i have wrapped the UserList inside Search HOC and provided 'Inside Users' as second argument. Final HOC is rendered inside App component.

You can find the attached codesandbox link for the above example.

Conclusion:

I have taken a very simple example to explain the usage higher order components. As we saw using HOC we can reuse our logic and optimise our application.