Back to all notes
Render Props Pattern: Pass a Renderer via a Named Prop
Similar to function children, but explicit—pass a render function to customize output.
Introduction
The render props pattern passes a function via a named prop (like renderItem) so consumers can control how data is rendered while sharing list or layout logic.
Why this matters
Function children are powerful but not always self‑documenting. Render props make the API explicit: you pass a renderItem (or similar) function to control how items are displayed.
The problem
We want a reusable List component that delegates how each item looks, without reimplementing list logic everywhere.
Inefficient approach
Mapping inline in every place you need a list creates duplication:
function Fruits() {
const items = ["Apple", "Banana", "Cherry"];
return (
<ul>
{items.map((item, index) => <li key={index}>{item}</li>)}
</ul>
);
}
function App() {
return (
<div>
<h1>Render Props Pattern</h1>
<Fruits />
</div>
);
}
export default App;
The solution
Accept a renderItem prop and call it for each item.
function List({ items, renderItem }) {
return (
<ul>
{items.map((item, index) => renderItem(item, index))}
</ul>
);
}
function App() {
const items = ["Apple", "Banana", "Cherry"];
return (
<div>
<h1>Render Props Pattern</h1>
<h2>List</h2>
<List items={items} renderItem={(item, index) => <li key={index}>{item}</li>} />
</div>
);
}
export default App;
Step-by-step
- Create a reusable
Listthat takesitemsandrenderItem. - Inside
List, map overitemsand callrenderItem(item, index). - In the parent, pass a function that returns a keyed
<li>. - Keep all item rendering logic outside of
List. - Reuse
Listwith differentrenderItemimplementations as needed.
Tips
- Name the render prop by intent (
renderRow,renderEmpty,renderHeader). - Keep the render function pure; avoid side effects inside it.
- If you pass several render functions, consider a Compound Components pattern instead.
Knowledge base
Problem snippet:
{items.map((item, index) => <li key={index}>{item}</li>)}
Solution snippet:
<List items={items} renderItem={(item, i) => <li key={i}>{item}</li>} />