Skip to main content

Higher-Order Component (HOC)

An HOC wraps a component in a function that returns an enhanced version, sharing cross-cutting logic like auth or theming. It composes well but adds wrapper nesting and hidden prop sources, so custom hooks now replace it for function components.

Type
Structural
When to Use
Share Cross Cutting Logic, Wrap Components, Inject Props, Compose Behavior

A higher-order component (HOC) is a function that accepts a component and returns a new, enhanced component. It is React's application of the decorator idea: rather than modifying a component, you wrap it to add props, state, or behavior. HOCs were the dominant way to share logic across components before Hooks arrived.

How It Works

An HOC has the shape withX(Component) -> EnhancedComponent. The wrapper renders the original component, passing through its own props plus the extra props it computes. For example withAuth(Profile) returns a component that reads the current user and renders <Profile user={user} {...props} />, redirecting to login when there is no session. Common library HOCs include connect() from React-Redux and withRouter.

Because HOCs compose, you can stack them: withAuth(withTheme(Page)). Each layer adds one concern. To behave well they should forward unknown props, set a readable displayName, and hoist static methods so the wrapped component stays usable.

When to Use It

Use an HOC to inject the same capability into many components — authentication gates, theming, analytics instrumentation, feature flags, or data subscriptions — without copying code. They remain useful in class-based codebases and in libraries that must support both class and function components. They also let you adapt a third-party component you cannot edit.

Trade-offs

HOCs introduce wrapper nesting ("wrapper hell") that complicates the component tree and React DevTools. Prop naming collisions are easy to create and hard to trace because the source of a prop is hidden in a wrapper. Static typing is awkward. For most logic-sharing needs in function components, custom hooks are now preferred: they share stateful logic without adding tree depth or obscuring prop origins. Many class-to-hooks migrations replace a stack of HOCs with a couple of hooks.

Related Patterns

Render props solve the same logic-sharing problem by passing a function as a child. Custom hooks are the modern replacement for both. Conceptually an HOC is the decorator pattern applied to components. The provider pattern is a complementary way to distribute shared values.

Example

function withAuth(Wrapped) {
  function WithAuth(props) {
    const user = useCurrentUser();
    if (!user) return <Redirect to="/login" />;
    return <Wrapped user={user} {...props} />;
  }
  WithAuth.displayName = `withAuth(${Wrapped.displayName || Wrapped.name})`;
  return WithAuth;
}

const ProtectedProfile = withAuth(Profile);

The gate is written once and applied to any page, but note how the user prop's origin is invisible at the call site — the chief reason hooks have largely superseded HOCs.