React Patterns — Compound, HOC, Render Props
Advertisement
React Patterns — Compound, HOC, Render Props
Understanding patterns helps you write more flexible, reusable components.
- React Patterns — Compound, HOC, Render Props
- Compound Components
- Higher-Order Components
- Render Props
- Custom Hooks (Modern Alternative)
- FAQ
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