Learnitweb

What is a Higher-Order Component (HOC) in React?

A Higher-Order Component (HOC) is a function that takes a component and returns a new enhanced component. This is a design pattern in React for reusing component logic.

Think of it as a “component factory” — a function that takes a component, enhances it, and returns a new component with added features or behavior.

Why Use Higher-Order Components?

React promotes the use of composition over inheritance. HOCs are a powerful tool to abstract shared logic and extend functionality without modifying existing components.

Key benefits include:

  1. Code Reusability Across Components
    If multiple components need the same behavior (like logging, theming, authorization), an HOC can wrap them with shared logic, reducing duplication.
  2. Separation of Concerns
    HOCs allow you to decouple logic from UI. The component focuses on rendering UI, while the HOC handles behaviors like fetching data, checking permissions, etc.
  3. Enhancing Third-Party Components
    You can wrap third-party components to add features without changing their source code — for example, adding error handling or state management.
  4. Conditional Rendering or Logic Injection
    HOCs can decide whether to render the wrapped component or something else, such as a login prompt or error message, based on props or state.

Syntax and Structure

A typical HOC looks like this:

const withEnhancement = (WrappedComponent) => {
  return function EnhancedComponent(props) {
    // Add custom logic here (side-effects, props manipulation, etc.)
    return <WrappedComponent {...props} />;
  };
};

Parameters:

  • WrappedComponent: The original React component you’re enhancing.
  • props: Props passed from the parent component.
  • EnhancedComponent: The new component returned by the HOC.

Basic Example: Logging Props

This HOC logs props every time the component renders:

function withLogger(WrappedComponent) {
  return function LoggerComponent(props) {
    console.log("Current props:", props);
    return <WrappedComponent {...props} />;
  };
}

// Usage
function Greeting({ name }) {
  return <h1>Hello, {name}!</h1>;
}

const GreetingWithLogger = withLogger(Greeting);

When you render <GreetingWithLogger name="Alice" />, it logs props and renders the original Greeting component.

Real-World Example: Access Control with Authentication

Suppose some components should only be visible to authenticated users:

function withAuth(WrappedComponent) {
  return function AuthenticatedComponent(props) {
    if (!props.isLoggedIn) {
      return <p>You must be logged in to view this content.</p>;
    }
    return <WrappedComponent {...props} />;
  };
}

Usage:

const Dashboard = () => <h2>Welcome to your dashboard</h2>;
const ProtectedDashboard = withAuth(Dashboard);

// Renders conditionally based on `isLoggedIn` prop
<ProtectedDashboard isLoggedIn={false} />;

Use Cases of HOCs (Expanded)

Here are common use cases where HOCs are beneficial, with more detail:

  1. Authentication and Access Control
    Restrict access to specific components based on login status, roles, or permissions. Useful in dashboards, admin panels, etc.
  2. Error Handling and Fallbacks
    Wrap components with a try-catch-like behavior to show a fallback UI when an error occurs during rendering or data fetching.
  3. Data Fetching and Injection
    Fetch data from an API and pass it as props to the child component — for example, a list of users, or product data.
  4. UI Enhancements
    Add animations, styling themes, or feature toggles to existing components without rewriting them.
  5. Tracking and Analytics
    Automatically log views, clicks, or scroll events across wrapped components for analytics or debugging purposes.

Internals of a HOC

Here’s what happens under the hood when you use a HOC:

  • The HOC does not modify the original component.
  • It returns a new functional component that:
    • Adds logic (e.g., modifies props, adds state)
    • Renders the original component using <WrappedComponent {...props} />

This pattern ensures immutability and reusability while providing powerful abstraction capabilities.

Best Practices for Using HOCs

  • Always Copy Props to Wrapped Components
    Always spread the props into the wrapped component to avoid missing critical data:
<WrappedComponent {...props} />
  • Use Meaningful Display Names
    Helps with debugging and DevTools inspection:
const name = WrappedComponent.displayName || WrappedComponent.name || "Component";
EnhancedComponent.displayName = `withLogger(${name})`;
  • Avoid Prop Collisions
    Ensure that props you inject (e.g., isAdmin, theme) don’t overwrite existing ones unless intended.
  • Use Composition Over Nesting
    Avoid deeply nested HOCs. Instead, compose them:
export default compose(withAuth, withLogger)(MyComponent);

HOC vs Custom Hooks (Modern Alternative)

FeatureHOCCustom Hook
FormFunction wrapping a componentFunction using hooks inside component
OutputNew componentLogic for use inside a component
Use CaseUI enhancement, conditional renderingSide-effects, stateful logic reuse
ReadabilityCan lead to nestingMore readable and modular
Preferred in modern React❌ Often verbose and abstract✅ More intuitive and concise