DEV Community

Cover image for Mastering React Design Patterns: HOC, Render Props, and Compound Components
Rakesh Reddy Peddamallu
Rakesh Reddy Peddamallu

Posted on

Mastering React Design Patterns: HOC, Render Props, and Compound Components

Introduction

React is one of the most popular frontend libraries, known for its component-based architecture. However, as applications grow, managing reusability, state, and structure becomes challenging. This is where design patterns come in. In this blog, we’ll explore three essential React patterns: Higher-Order Components (HOC), Render Props, and Compound Components. These patterns help in writing scalable and maintainable code.


1️⃣ Higher-Order Components (HOC)

What is a Higher-Order Component?

A Higher-Order Component (HOC) is a function that takes a component and returns an enhanced component with additional functionality. HOCs are great for code reuse and logic abstraction.

Example: Logging User Activity with an HOC

import React from "react";

// Higher-Order Component
function withLogger(WrappedComponent) {
  return function EnhancedComponent(props) {
    console.log(`Component ${WrappedComponent.name} rendered!`);
    return <WrappedComponent {...props} />;
  };
}

// Regular Component
function Button({ label }) {
  return <button>{label}</button>;
}

// Enhanced Component
const ButtonWithLogger = withLogger(Button);

export default function App() {
  return <ButtonWithLogger label="Click Me" />;
}
Enter fullscreen mode Exit fullscreen mode

When to Use HOCs?

✅ Authentication & Authorization

✅ Logging & Analytics

✅ Data Fetching & Caching


2️⃣ Render Props

What is Render Props?

A Render Prop is a function passed as a prop to a component. The child component then calls this function to render dynamic content. This pattern is helpful when sharing logic between components.

Example: Mouse Tracker Component

import React, { useState } from "react";

// Component using Render Props
function MouseTracker({ render }) {
  const [position, setPosition] = useState({ x: 0, y: 0 });

  const handleMouseMove = (event) => {
    setPosition({ x: event.clientX, y: event.clientY });
  };

  return <div onMouseMove={handleMouseMove}>{render(position)}</div>;
}

// Using MouseTracker in App
export default function App() {
  return (
    <MouseTracker
      render={({ x, y }) => (
        <h2>
          Mouse Position: ({x}, {y})
        </h2>
      )}
    />
  );
}
Enter fullscreen mode Exit fullscreen mode

When to Use Render Props?

✅ Handling state across multiple components

✅ Animation effects

✅ Form handling


3️⃣ Compound Components

What is a Compound Component?

A Compound Component is a pattern where multiple components work together as a single unit, allowing for a clean and flexible API. This pattern is useful for designing reusable UI components like tabs, modals, and accordions.

Example: Custom Tabs Component

import React, { useState } from "react";

function Tabs({ children }) {
  const [activeIndex, setActiveIndex] = useState(0);

  return React.Children.map(children, (child, index) => {
    if (child.type === TabList) {
      return React.cloneElement(child, { activeIndex, setActiveIndex });
    }
    if (child.type === TabPanel) {
      return activeIndex === index - 1 ? child : null; // Only show active panel
    }
    return child;
  });
}

function TabList({ children, activeIndex, setActiveIndex }) {
  return React.Children.map(children, (child, index) =>
    React.cloneElement(child, {
      isActive: activeIndex === index,
      onClick: () => setActiveIndex(index),
    })
  );
}

function Tab({ children, isActive, onClick }) {
  return (
    <button onClick={onClick} style={{ fontWeight: isActive ? "bold" : "normal" }}>
      {children}
    </button>
  );
}

function TabPanel({ children }) {
  return <div>{children}</div>;
}

// Usage
export default function App() {
  return (
    <Tabs>
      <TabList>
        <Tab>Tab 1</Tab>
        <Tab>Tab 2</Tab>
      </TabList>
      <TabPanel>Content of Tab 1</TabPanel>
      <TabPanel>Content of Tab 2</TabPanel>
    </Tabs>
  );
}
Enter fullscreen mode Exit fullscreen mode

When to Use Compound Components?

Tabs & Accordions

Modals & Dialogs

Dropdown Menus


Conclusion

React Design Patterns help in writing scalable, reusable, and maintainable code. Here's a quick summary:

Pattern Use Case Example
Higher-Order Components (HOC) Code reuse, authentication, analytics withLogger(Component)
Render Props Dynamic UI rendering, sharing state {render: (props) => <Component {...props} />}
Compound Components Designing flexible, reusable UI components <Tabs><TabList><Tab /></TabList><TabPanel /></Tabs>

Each pattern has its strengths, and choosing the right one depends on the problem you are solving. Mastering these patterns will make you a better React developer! 🚀

Which pattern do you use the most? Let me know in the comments! 👇

Top comments (1)

Collapse
 
brense profile image
Rense Bakker

Nice examples, especially of the compound components pattern. I would like to add though that you should be really careful with render props, because what you put in them can very easily result in very bad performing react code, unless you properly memoize everything.

In general it is recommended to use custom hooks instead of render props and HoCs.