Master React patterns like compound components, render props, and higher-order components for clean reusable patterns.
const Accordion = ({ children }) => {
const [active, setActive] = useState(null);
return (
<AccordionContext.Provider value={{ active, setActive }}>
{children}
</AccordionContext.Provider>
);
};
const AccordionItem = ({ id, title, children }) => {
const { active, setActive } = useContext(AccordionContext);
return (
<div>
<button onClick={() => setActive(id)}>{title}</button>
{active === id && <div>{children}</div>}
</div>
);
};
<Accordion>
<AccordionItem id="1" title="Section 1">Content 1</AccordionItem>
<AccordionItem id="2" title="Section 2">Content 2</AccordionItem>
</Accordion>const MouseTracker = ({ render }) => {
const [pos, setPos] = useState({ x: 0, y: 0 });
const handleMouseMove = (e) => {
setPos({ x: e.clientX, y: e.clientY });
};
return (
<div onMouseMove={handleMouseMove}>
{render(pos)}
</div>
);
};
<MouseTracker render={({ x, y }) => (
<p>Mouse at {x}, {y}</p>
)} />children function is a special render prop pattern.<MouseTracker>
{({ x, y }) => <p>Position: {x}, {y}</p>}
</MouseTracker>const withAuth = (Component) => {
return (props) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
checkAuth().then(u => {
setUser(u);
setLoading(false);
});
}, []);
if (loading) return <p>Loading...</p>;
if (!user) return <p>Not authenticated</p>;
return <Component user={user} {...props} />;
};
};
const Dashboard = ({ user }) => <h1>Welcome {user.name}</h1>;
const ProtectedDashboard = withAuth(Dashboard);<Form>
<Form.Field name="email" />
<Form.Field name="password" />
<Form.Submit>Login</Form.Submit>
</Form><DataFetcher url="/api/users" render={data => (
<UserList users={data} />
)} />const enhancedComponent = withDataFetching(MyComponent);function useMousePosition() {
const [pos, setPos] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleMove = (e) => setPos({ x: e.clientX, y: e.clientY });
window.addEventListener('mousemove', handleMove);
return () => window.removeEventListener('mousemove', handleMove);
}, []);
return pos;
}
function MyComponent() {
const pos = useMousePosition();
return <p>Position: {pos.x}, {pos.y}</p>;
}Use compound components when you want a flexible, declarative API where parent and child components share implicit state (like a Tabs/Tab pair). Use render props when you need to inject dynamic content or logic into a single component that consumers control directly.
Extract the logic into a custom hook and call it in each component that needs it. This is the modern recommended approach — it avoids wrapper components entirely and keeps the component tree flat.
An HOC wraps a component and returns a new one, adding behavior at the component level; it shows up in the React tree and can obscure the component hierarchy. A custom hook shares logic at the function level without adding any components to the tree, making it easier to trace and debug.
Wrapper hell happens when multiple HOCs are stacked around a single component, making the component tree and props difficult to follow. Refactor each HOC's logic into a separate custom hook and call them directly inside the component instead.
Use React context inside the compound component — the parent holds the shared state and provides it via a context, and each child reads from that context directly. This keeps the public API clean while avoiding the need to pass props through every intermediate child.