React Patterns: HOC vs Render Props vs Hooks (Modern Perspective)

React has evolved significantly over the years. Many patterns that were once widely used have been replaced by simpler and more powerful alternatives. In this article we compare three important patterns — Higher-Order Components (HOC), Render Props and Hooks — focusing on when to use each, code examples, pros and cons, and modern best practices.

1. Higher-Order Components (HOC)

A Higher-Order Component is a function that takes a component and returns a new, enhanced component.

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

const EnhancedButton = withLogger(Button);

Pros: good for cross-cutting concerns such as auth and logging; reusable logic across many components.

Cons: wrapper hell (deep nesting), hard to debug, props collision issues, less intuitive for beginners.

2. Render Props

Render Props is a pattern where a component shares its state or logic by using a function as a prop. Instead of wrapping components like a HOC, you pass a function that controls what gets rendered.

A component receives a function and uses it to decide what to render.

Let's build a mouse tracker:

function MouseTracker({ render }) {
  const [position, setPosition] = React.useState({ x: 0, y: 0 });

  function handleMouseMove(e) {
    setPosition({ x: e.clientX, y: e.clientY });
  }

  return (
    <div style={{ height: "100vh" }} onMouseMove={handleMouseMove}>
      {render(position)}
    </div>
  );
}

function App() {
  return (
    <MouseTracker
      render={({ x, y }) => (
        <div>
          <h2>Mouse Position</h2>
          <p>X: {x}</p>
          <p>Y: {y}</p>
        </div>
      )}
    />
  );
}

How it works

  1. MouseTracker holds the state (the logic).
  2. It tracks mouse movement.
  3. It does not decide the UI.
  4. Instead, it calls render(position).
  5. The parent decides how the UI should look.

Before Hooks existed, this pattern solved a big problem: how can we reuse logic without duplicating code? It enabled logic reuse, UI flexibility and separation of concerns.

Pros: very flexible UI composition, explicit data flow, works well in reusable utility components.

Cons: functions inside JSX make nesting messy, hard to read in deep compositions, can lead to callback-based UI complexity, and has been replaced in most cases by Hooks.

Today Render Props is mostly found in libraries (older React Router versions, animation libraries), data-fetching components, legacy codebases and some advanced UI composition cases.

3. Hooks (Modern React Approach)

Hooks introduced a new way of thinking: instead of organizing code around lifecycles or wrapper patterns, we organize logic around reusable functions. They let you extract and reuse stateful logic without changing your component hierarchy — a shift from wrapping components to composing logic through functions.

function useMousePosition() {
  const [position, setPosition] = React.useState({ x: 0, y: 0 });

  React.useEffect(() => {
    const handler = (e) => setPosition({ x: e.clientX, y: e.clientY });
    window.addEventListener("mousemove", handler);
    return () => window.removeEventListener("mousemove", handler);
  }, []);

  return position;
}

function App() {
  const position = useMousePosition();
  return <h1>{position.x}, {position.y}</h1>;
}

Why Hooks changed React

  • No wrapper components (unlike HOC)
  • No nested render functions (unlike Render Props)
  • Logic becomes composable and reusable
  • Better separation between UI and behavior

Strengths: clean and minimal structure, easy to compose many logic units, highly reusable through custom hooks, readable in medium and large codebases, best integration with the modern React ecosystem.

Limitations: you must follow the Rules of Hooks, overusing custom hooks can fragment logic, abstraction design needs discipline, and side effects can become complex if not structured well.

Hooks are not just a syntactic improvement — they represent a shift in mental model, from inheritance and wrappers to the functional composition of behavior. That is why they replaced most HOC and Render Props use cases.

When to Use What?

Use Hooks when building new React applications, when you need reusable logic, and when you want a clean, scalable architecture.

Use HOC when working with legacy systems or older libraries that require it.

Use Render Props when you need dynamic UI injection from libraries or are dealing with older composition patterns.

Conclusion

In modern React development, Hooks have become the foundation of component design. They simplify logic reuse, reduce structural complexity and enable a more functional way of thinking about UI.

Older patterns like HOC and Render Props are not obsolete — they still exist in many libraries and legacy architectures, and understanding them matters for maintaining real-world code. A strong React developer is not someone who only knows Hooks, but someone who understands why Hooks replaced the older patterns and when those patterns still make sense.

In complex UIs — dashboards, design tools or 3D web experiences — Hooks provide a scalable foundation for organizing interaction logic, state and side effects. Mastering them is less about syntax and more about learning how to structure behavior in modern front-end systems.