Back to all posts

React JS HOC: Example and Usage

Sutharsan GS

Sutharsan G

5 min read

In React, Higher-Order Components (HOCs) are a powerful pattern for reusing component logic. HOCs are not a feature of React itself but rather a design pattern used to enhance or modify a component’s behavior by wrapping it with additional functionality. The concept of HOCs is based on the principle of higher-order functions in JavaScript, which are functions that take other functions as arguments or return them.

This blog post will explain what HOCs are, how they work, and provide an example of how to create and use them in your React projects.

What is a Higher-Order Component?

A Higher-Order Component is a function that takes a component and returns a new component. HOCs allow you to reuse component logic, add extra functionality, and manipulate the props of the wrapped component in a clean and scalable way.

Think of an HOC as a "wrapper" around a component, which enhances or modifies the behavior of the component.

Key Features of HOCs:

  1. Reusability: They allow you to reuse logic across multiple components.
  2. Composition: You can compose multiple HOCs together to combine behaviors.
  3. Separation of Concerns: By separating logic from UI, they help keep components clean and focused on their primary responsibility.

Important Note:

HOCs don’t modify the original component; they return a new component with enhanced behavior.

Example: Creating a Simple HOC

Let’s walk through an example of how to create a Higher-Order Component in React.

1. Define the HOC

We will create a simple HOC called withLoading that adds loading functionality to a component. The withLoading HOC will show a loading spinner if the loading prop is true and will display the wrapped component once the data has finished loading.

import React from 'react';

// HOC that adds loading functionality to the wrapped component
const withLoading = (WrappedComponent) => {
  return function WithLoading(props) {
    // Check if the 'loading' prop is true
    if (props.loading) {
      return <div>Loading...</div>;
    }

    // If not loading, render the wrapped component with its props
    return <WrappedComponent {...props} />;
  };
};

export default withLoading;

2. Use the HOC with a Component

Now, let's use the withLoading HOC to enhance a UserList component. This component will simulate fetching user data from an API.

import React, { useState, useEffect } from 'react';
import withLoading from './withLoading';

// Simulate fetching user data
const UserList = ({ users }) => {
  return (
    <ul>
      {users.map(user => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
};

// Wrap the UserList component with the withLoading HOC
const UserListWithLoading = withLoading(UserList);

const App = () => {
  const [loading, setLoading] = useState(true);
  const [users, setUsers] = useState([]);

  useEffect(() => {
    setTimeout(() => {
      setUsers([
        { id: 1, name: 'John Doe' },
        { id: 2, name: 'Jane Smith' },
        { id: 3, name: 'David Johnson' },
      ]);
      setLoading(false);
    }, 2000); // Simulate a 2-second delay
  }, []);

  return (
    <div>
      <h1>User List</h1>
      <UserListWithLoading loading={loading} users={users} />
    </div>
  );
};

export default App;

How it Works:

  • The UserList component receives a users prop and displays them in a list.
  • The withLoading HOC wraps the UserList component and adds a loading state. If loading is true, it shows a loading message; otherwise, it renders the UserList with the user data.
  • In the App component, we simulate fetching user data with a 2-second delay using setTimeout to show how the loading state works.

When to Use HOCs

HOCs are most useful in situations where you have common functionality that needs to be applied to multiple components, such as:

  • Authentication: Wrapping a component with an authentication HOC that checks whether the user is logged in.
  • Error Handling: Wrapping a component with an error boundary to catch JavaScript errors in the component tree.
  • Authorization: Wrapping components to restrict access to certain parts of the UI based on user roles or permissions.
  • Data Fetching: Wrapping components with logic for handling loading states, API calls, and error handling.

Pros and Cons of Using HOCs

Pros:

  • Code Reusability: HOCs help avoid duplication of logic across components.
  • Separation of Concerns: They allow you to separate the logic of data fetching, authentication, etc., from the presentation.
  • Composability: HOCs can be composed together, allowing you to layer multiple behaviors.

Cons:

  • Wrapper Hell: When you chain multiple HOCs, you may run into a situation called "wrapper hell," where debugging becomes challenging as the component tree gets deeply nested.
  • Props Conflicts: Passing props down the chain can sometimes lead to conflicts, especially if the HOC modifies props in unexpected ways.

Conclusion

Higher-Order Components (HOCs) are a powerful pattern in React that allow you to reuse logic across components and separate concerns in your application. By creating HOCs, you can easily enhance the behavior of your components, such as adding loading states, authentication checks, and error handling.

While HOCs are incredibly useful, it’s important to use them judiciously to avoid complexity, and remember that React Hooks (introduced in React 16.8) provide an alternative way of sharing logic, which may be more appropriate in some cases.

With a clear understanding of HOCs and their use cases, you can start applying them to your own React projects to make your code more modular and maintainable.

Additional Resources