Render Props Pattern
function ComponentName({ render }) {
// shared logic
return <div>{render(data)}</div>;
}
<ComponentName render={data => <p>{data}</p>} />
What a Render Prop Is
A render prop is a prop whose value is a function that returns JSX. Instead of a component deciding what to display internally, it calls this function and renders whatever it returns.
This lets the component supply data or behavior while the caller controls the exact markup.
Example: What a Render Prop Is
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function MouseTracker({ render }) {
const [pos, setPos] = React.useState({ x: 0, y: 0 });
return (
<div onMouseMove={e => setPos({ x: e.clientX, y: e.clientY })} style={{height: 100, border: "1px solid #333"}}>
{render(pos)}
</div>
);
}
function App() {
return <MouseTracker render={pos => <p>Mouse at {pos.x}, {pos.y}</p>} />;
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>
Using 'children' as a Render Prop
Instead of a custom-named prop, you can use the built-in children prop as a function. React doesn't require children to be JSX — it can be any value, including a function, which the component then calls and renders wherever it wants.
Example: Using 'children' as a Render Prop
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function Toggle({ children }) {
const [on, setOn] = React.useState(false);
return children({ on, toggle: () => setOn(o => !o) });
}
function App() {
return (
<Toggle>
{({ on, toggle }) => (
<button onClick={toggle}>{on ? "Visible" : "Hidden"}</button>
)}
</Toggle>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>
Render Props vs. Custom Hooks
Everything a render-props component can do, a custom hook can usually do more simply, without adding an extra layer of JSX nesting. The MouseTracker example above can be rewritten as a useMousePosition hook that any component calls directly, no wrapping component required.
Example: Render Props vs. Custom Hooks
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function useMousePosition() {
const [pos, setPos] = React.useState({ x: 0, y: 0 });
const handleMove = e => setPos({ x: e.clientX, y: e.clientY });
return [pos, handleMove];
}
function App() {
const [pos, handleMove] = useMousePosition();
return (
<div onMouseMove={handleMove} style={{height: 100, border: "1px solid #333"}}>
<p>Mouse at {pos.x}, {pos.y} (hook version, no wrapper needed)</p>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<App />);
</script>
</body>
</html>
- Forgetting that the prop doesn't have to be literally called render — any prop that's a function returning JSX counts as a render prop.
- Creating a new inline function on every render for the render prop, which can cause unnecessary re-renders in optimized child components.
- Overusing render props today when a custom hook would be simpler — hooks have replaced most historical use cases for this pattern.
- The render-props pattern is a component that takes a function as a prop and calls it to determine what to render.
- It lets a component share stateful logic while letting the caller fully control the resulting UI.
- It predates hooks and was the primary way to share logic between components before React 16.8.
- Custom hooks now cover most of what render props used to be needed for, but the pattern still appears in some libraries.
Works in any React version supporting function components and props (React 0.14+); most commonly seen in pre-Hooks (pre-16.8) codebases.
Chapter Quiz — Complete all 10 topics to unlock
0/10 topics done
Complete these topics first: