
Render Props Pattern
Render props is a technique where a component receives a function as a prop and calls it to determine what to render. It enables behavior sharing without HOC wrapper nesting.
Basic Shape
function MouseTracker({ render }) {
const [position, setPosition] = useState({ x: 0, y: 0 });
return (
<div onMouseMove={e => setPosition({ x: e.clientX, y: e.clientY })}>
{render(position)}
</div>
);
}
// Usage
<MouseTracker render={({ x, y }) => (
<p>Mouse at {x}, {y}</p>
)} /> The consumer controls what renders; the provider controls when and with what data.
Children as Function
The children prop can be the render function, which reads more naturally:
function MouseTracker({ children }) {
const [position, setPosition] = useState({ x: 0, y: 0 });
return (
<div onMouseMove={e => setPosition({ x: e.clientX, y: e.clientY })}>
{children(position)}
</div>
);
}
<MouseTracker>
{({ x, y }) => <Cursor x={x} y={y} />}
</MouseTracker> Common Use Cases
Virtualization:
<VirtualList
items={rows}
renderItem={(item) => <Row key={item.id} data={item} />}
/> Form fields (Formik-style):
<Field name="email">
{({ field, meta }) => (
<div>
<input {...field} />
{meta.error && <span>{meta.error}</span>}
</div>
)}
</Field> Toggle:
function Toggle({ children }) {
const [on, setOn] = useState(false);
return children({ on, toggle: () => setOn(v => !v) });
}
<Toggle>
{({ on, toggle }) => (
<button onClick={toggle}>{on ? 'ON' : 'OFF'}</button>
)}
</Toggle> Render Props vs Custom Hooks
Custom hooks replaced most render prop use cases. Compare:
// Render prop
<MouseTracker render={pos => <Cursor {...pos} />} />
// Custom hook — simpler, no extra nesting
function CursorComponent() {
const pos = useMousePosition();
return <Cursor {...pos} />;
} Prefer hooks for new code. Use render props when:
- You need the parent to control the rendering context (e.g., inside a specific DOM element)
- Building a headless component library where consumers need full render control
Performance Caveat
Inline render functions are new references on every parent render. If the receiving component uses React.memo, it still re-renders because the prop changed. Memoize with useCallback or restructure to avoid.









