React Patterns
Design patterns help build flexible, reusable component APIs. Choose the pattern based on what you need to share.
Compound Components
Components that work together and share implicit state.
<Tabs>
<Tabs.List>
<Tabs.Tab>One</Tabs.Tab>
<Tabs.Tab>Two</Tabs.Tab>
</Tabs.List>
<Tabs.Panel>Content 1</Tabs.Panel>
<Tabs.Panel>Content 2</Tabs.Panel>
</Tabs>
Internally, Tabs manages which tab is active and passes that state down via context.
const TabsContext = createContext();
function Tabs({ children }) {
const [active, setActive] = useState(0);
return (
<TabsContext.Provider value={{ active, setActive }}>
{children}
</TabsContext.Provider>
);
}
Render Props
A component receives a function as a prop and calls it with internal state.
function MouseTracker({ render }) {
const [pos, setPos] = useState({ x: 0, y: 0 });
return (
<div onMouseMove={(e) => setPos({ x: e.clientX, y: e.clientY })}>
{render(pos)}
</div>
);
}
// Usage
<MouseTracker render={({ x, y }) => <p>Mouse at {x}, {y}</p>} />
Higher-Order Components (HOC)
A function that takes a component and returns an enhanced version.
function withAuth(Component) {
return function Protected(props) {
const { user } = useAuth();
if (!user) return <Redirect to="/login" />;
return <Component {...props} user={user} />;
};
}
const ProtectedDashboard = withAuth(Dashboard);
When to Use Each
- Compound components — when building complex UI with shared state (tabs, accordions, menus)
- Render props — when you need to share logic without wrapping components
- HOCs — for cross-cutting concerns like auth, logging, or data fetching
Modern Alternatives
- Hooks have replaced most HOC and render prop use cases
- Context + custom hooks replace compound component boilerplate
- Use hooks first; reach for patterns only when hooks aren’t enough
Best Practices
- Favor hooks and context over HOCs and render props
- Use compound components for complex, related UI elements
- Keep HOCs focused on a single concern
- Name HOCs with the
withprefix for clarity - Avoid prop collisions when wrapping with HOCs
Common Mistakes
- Over-engineering simple components with unnecessary patterns
- Creating deep HOC chains that are hard to debug
- Forwards refs correctly when wrapping with HOCs
- Not setting display names on HOCs (makes DevTools confusing)
- Using render props when a simple hook would work