React Patterns — Compound, HOC, Render Props

Sanjeev SharmaSanjeev Sharma
2 min read

Advertisement

React Patterns — Compound, HOC, Render Props

Understanding patterns helps you write more flexible, reusable components.

Compound Components

Build components from smaller parts:

function Dialog({ isOpen, onClose, children }) {
  if (!isOpen) return null
  return (
    <div className="modal">
      {children}
    </div>
  )
}

Dialog.Header = function({ children }) {
  return <div className="modal-header">{children}</div>
}

Dialog.Body = function({ children }) {
  return <div className="modal-body">{children}</div>
}

Dialog.Footer = function({ children }) {
  return <div className="modal-footer">{children}</div>
}

// Usage
<Dialog isOpen={open} onClose={onClose}>
  <Dialog.Header>Title</Dialog.Header>
  <Dialog.Body>Content</Dialog.Body>
  <Dialog.Footer>
    <button onClick={onClose}>Close</button>
  </Dialog.Footer>
</Dialog>

Higher-Order Components

Wrap components to add functionality:

function withAuth<P extends object>(
  Component: React.ComponentType<P>
) {
  return function Protected(props: P) {
    const { user } = useAuth()

    if (!user) return <Redirect to="/login" />

    return <Component {...props} user={user} />
  }
}

// Usage
const ProtectedPage = withAuth(Page)

Render Props

Pass rendering logic as props:

function Mouse({ children }: { children: (props: Position) => React.ReactNode }) {
  const [position, setPosition] = useState({ x: 0, y: 0 })

  return (
    <div
      onMouseMove={(e) => setPosition({ x: e.clientX, y: e.clientY })}
    >
      {children(position)}
    </div>
  )
}

// Usage
<Mouse>
  {(position) => <div>Mouse at {position.x}, {position.y}</div>}
</Mouse>

Custom Hooks (Modern Alternative)

function useMouse() {
  const [position, setPosition] = useState({ x: 0, y: 0 })

  useEffect(() => {
    function handleMouseMove(e: MouseEvent) {
      setPosition({ x: e.clientX, y: e.clientY })
    }

    window.addEventListener('mousemove', handleMouseMove)
    return () => window.removeEventListener('mousemove', handleMouseMove)
  }, [])

  return position
}

// Usage - cleaner!
function MouseTracker() {
  const position = useMouse()
  return <div>Mouse at {position.x}, {position.y}</div>
}

FAQ

Q: Should I use render props or hooks? A: Prefer hooks - simpler and more composable.

Q: When is HOC appropriate? A: For cross-cutting concerns like auth, theming, or analytics.

Q: Can I combine patterns? A: Yes, but keep it simple. Prefer hooks first.


Patterns help you structure React code for maintainability and reusability.

Advertisement

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro