Render Props
Render props pass a function as a prop (or child) that receives data from the provider component. The caller decides how to render using that data — flexible composition before hooks dominated.
Function as Prop <Mouse render={({ x, y }) => <Cursor x={x} y={y} />} /> — Mouse tracks position; render prop decides UI. Same idea as children-as-function.
Custom hooks often replace render props today, but the pattern appears in libraries like Headless UI and React Router's <Route render>.
function DataLoader({ url, children }) {
const [data, setData] = useState(null);
useEffect(() => { fetch(url).then(r => r.json()).then(setData); }, [url]);
return children({ data, loading: !data });
}
<DataLoader url="/api/user">
{({ data, loading }) => loading ? <Spinner /> : <Profile user={data} />}
</DataLoader> Children as function is a render prop variant.
Render Prop Variants <Component render={(state) => <UI {...state} />} />
<Component>{(state) => <UI {...state} />}</Component> Prop name need not be render — children as function is common. Caller controls rendering; provider owns state/logic. Avoid inline render functions in hot paths if memoization matters. Hooks extract same logic with less JSX nesting. Composition Patterns Compared Render props, HOCs, and hooks.
Pattern Pros Render props Explicit data flow in JSX HOCs Wrap without changing JSX tree much Custom hooks Cleanest for reuse today Children slot Simple composition Context Deep tree without prop drilling
Render Props in Libraries Headless UI, Downshift, and Formik use render props or function children to give full UI control while owning behavior and accessibility.
Render Prop to Hook Refactor Mouse tracker render prop becomes useMouse() hook returning { x, y } — component uses values directly without wrapper.
function useMouse() {
const [pos, setPos] = useState({ x: 0, y: 0 });
useEffect(() => {
const move = (e) => setPos({ x: e.clientX, y: e.clientY });
window.addEventListener('mousemove', move);
return () => window.removeEventListener('mousemove', move);
}, []);
return pos;
} Common Mistakes Deep nesting of multiple render prop components (callback pyramid). Using render props when a simple hook suffices. Inline render functions breaking memoization unnecessarily. Confusing render props with controlled component props. Key Takeaways Render props share logic via function props/children. Flexible UI control remains with the consumer. Custom hooks are the modern equivalent for most cases. Still used in headless component libraries.
Pro Tip
When you see {children(state)} in library source, recognize it as render props — pass a function child to customize UI.
Higher-Order Components Go to next item