Back to all notes

Higher‑Order Components: The Legacy Pattern You'll Still Meet

Wrap a component to inject extra props. Useful to understand, even if hooks are preferred today.

1 min read

Introduction

A Higher‑Order Component (HOC) is a function that takes a component and returns a new one with extra behavior or props. Even though hooks are preferred today, HOCs still appear in older codebases and some libraries.

Why this matters

A Higher‑Order Component (HOC) is a function that takes a component and returns a new component with added behavior or props. While hooks replaced most HOCs, you’ll still see them in older codebases and some libraries.

The problem

We want to provide a user prop to a component without threading it through every usage.

Inefficient approach

Manually passing user everywhere makes usage noisy:

function UserProfile({ user }) {
  return (
    <div>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
    </div>
  );
}

function App() {
  const user = { name: "John Doe", email: "john@example.com" };
  return (
    <div>
      <h1>Higher-Order Components</h1>
      <UserProfile user={user} />
    </div>
  );
}

export default App;

The solution

Write a withUser HOC that returns an enhanced component.

function withUser(Component) {
  const user = { name: "John Doe", email: "john@example.com" };
  return function EnhancedComponent(props) {
    return <Component {...props} user={user} />;
  };
}

function UserProfile({ user }) {
  return (
    <div>
      <h2>{user.name}</h2>
      <p>{user.email}</p>
    </div>
  );
}

const EnhancedUserProfile = withUser(UserProfile);

function App() {
  return (
    <div>
      <h1>Higher-Order Components</h1>
      <EnhancedUserProfile />
    </div>
  );
}

export default App;

Knowledge base

Problem snippet:

function App() {
  const user = { name: "John Doe", email: "john@example.com" };
  return <UserProfile user={user} />;
}

Solution snippet:

const EnhancedUserProfile = withUser(UserProfile);
<EnhancedUserProfile />

Tips

  • Name HOCs by behavior: withAuth, withFeatureFlags, etc.
  • Preserve static properties if needed (many libraries provide helpers).
  • Prefer hooks for new code; reach for HOCs mainly when interop requires it.