Higher Order Components (HOC)

A Higher Order Component (HOC) is a pattern in React for reusing component logic. It is a function that takes a component as an argument and returns a new, enhanced component. The original component is wrapped with additional behavior without modifying it directly.

HOCs are not a React API feature — they are a design pattern based on JavaScript's ability to treat functions as first-class values. They were widely used before React Hooks were introduced, and are still relevant in certain scenarios today.

The Concept — Wrapping Behavior

A real-world analogy: think of a HOC like a gift wrapper. The gift (the original component) remains unchanged. The wrapping paper (the HOC) adds presentation and packaging around it without altering the gift itself.

Another analogy: a security guard at a door. The guard does not change the person trying to enter — they just add a layer of authentication logic. If authorized, the person enters. If not, they are redirected. The HOC behaves the same way for components.

Basic HOC Structure


function withExtraFeature(WrappedComponent) {
  return function EnhancedComponent(props) {
    // Add extra logic here
    return <WrappedComponent {...props} extraProp="value" />;
  };
}

The HOC accepts WrappedComponent as a parameter and returns a new function (component) that renders the original with added capabilities. The spread {...props} passes all original props through, ensuring the wrapped component still receives everything it needs.

Example 1 — withLoading HOC

A HOC that adds a loading state to any component — useful when data is being fetched:


function withLoading(WrappedComponent) {
  return function WithLoadingComponent({ isLoading, ...props }) {
    if (isLoading) {
      return <p>Loading, please wait...</p>;
    }
    return <WrappedComponent {...props} />;
  };
}

// A simple list component
function UserList({ users }) {
  return (
    <ul>
      {users.map((user) => (
        <li key={user.id}>{user.name}</li>
      ))}
    </ul>
  );
}

// Enhanced version with loading support
const UserListWithLoading = withLoading(UserList);

function App() {
  const isLoading = false;
  const users = [
    { id: 1, name: "Alice" },
    { id: 2, name: "Bob" },
  ];

  return <UserListWithLoading isLoading={isLoading} users={users} />;
}

The withLoading HOC can now be applied to any component — withLoading(ProductList), withLoading(ArticleFeed), and so on — without repeating the loading logic in each one.

Example 2 — withAuthentication HOC

A HOC that protects a component by checking if the user is logged in:


import { Navigate } from 'react-router-dom';

function withAuthentication(WrappedComponent) {
  return function AuthenticatedComponent(props) {
    const isLoggedIn = Boolean(localStorage.getItem("token"));

    if (!isLoggedIn) {
      return <Navigate to="/login" />;
    }

    return <WrappedComponent {...props} />;
  };
}

function AdminPage() {
  return <h2>Welcome, Admin!</h2>;
}

const ProtectedAdminPage = withAuthentication(AdminPage);

Now ProtectedAdminPage automatically redirects to the login page if the user is not authenticated. The original AdminPage component has no knowledge of authentication — the HOC handles it.

Example 3 — withLogger HOC

A HOC that logs whenever a component renders — useful for debugging:


function withLogger(WrappedComponent) {
  return function LoggedComponent(props) {
    console.log(`[${WrappedComponent.name}] rendered with props:`, props);
    return <WrappedComponent {...props} />;
  };
}

function ProductCard({ name, price }) {
  return <div>{name} — {price}</div>;
}

const LoggedProductCard = withLogger(ProductCard);

HOC Naming Convention

HOCs are conventionally named with a with prefix — withLoading, withAuth, withLogger, etc. This makes it immediately clear that the function is a Higher Order Component.

The component returned by a HOC should also be given a meaningful display name for debugging purposes. This is visible in React DevTools:


function withLoading(WrappedComponent) {
  function WithLoadingComponent({ isLoading, ...props }) {
    if (isLoading) return <p>Loading...</p>;
    return <WrappedComponent {...props} />;
  }

  // Set display name for React DevTools
  WithLoadingComponent.displayName = `WithLoading(${WrappedComponent.name})`;

  return WithLoadingComponent;
}

HOCs vs Custom Hooks

With the introduction of Hooks in React 16.8, many use cases for HOCs can now be handled with Custom Hooks. Here is a comparison:

  • HOCs wrap a component and add behavior at the component level — they affect rendering and what gets displayed.
  • Custom Hooks share stateful logic between components without affecting the component tree structure — they do not add wrapper elements.

When the added behavior is about controlling what renders (loading states, access control), HOCs are a natural fit. When the behavior is about sharing stateful logic (data fetching, subscriptions), Custom Hooks are cleaner. In modern React, Custom Hooks are generally preferred, but HOCs remain valuable for cross-cutting concerns like authentication and error handling.

Key Points

  • A Higher Order Component is a function that takes a component and returns a new, enhanced component.
  • HOCs follow the with naming convention: withLoading, withAuth, withLogger.
  • Always pass props through using {...props} to avoid breaking the wrapped component.
  • HOCs are great for cross-cutting concerns: loading states, authentication, logging.
  • In modern React, Custom Hooks often replace HOCs for stateful logic — but HOCs remain useful for render control.
  • Set displayName on the HOC output for better React DevTools debugging.

The next topic covers Redux — State Management, a popular solution for managing complex, application-wide state in large React projects.

Leave a Comment

Your email address will not be published. Required fields are marked *