Render Props Pattern
A render prop is a prop whose value is a function that returns JSX, letting one component own some state or behavior while the parent decides exactly what to render with it — most often written as a function passed as children . It was the classic way to share reusable logic before hooks arrived.
Learn Render Props Pattern in our free React course — an interactive lesson with runnable examples, a practice exercise and a quick recall.
Part of the free React course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
' throw 'children is not a function'?", options: ["Mouse is missing a key", "p is not a valid tag", "Mouse needs a ref", "children must be a function, but a JSX element was passed"], answer: 3, explanation: "The component calls children(data); passing an element instead of a function breaks that call." }, , , ]; const faqItems = [ , { q: "Is 'children as a function' the same thing?", a: "Yes, it's the most common form. Instead of a prop literally named render, you pass a function as children: {(pos) =>
1️⃣ A Prop That Is a Function Returning JSX
The component holds the logic — say, tracking the mouse — and accepts a render prop. Instead of rendering fixed markup, it calls props.render(data) and returns whatever the parent's function produces. The same component can power totally different UIs.
2️⃣ Children as a Function
The idiomatic version passes the function as children instead of a named prop, and the component calls children(data) . It reads more naturally because the function sits right between the tags, exactly where children normally go.
3️⃣ Render Props vs Custom Hooks
A custom hook like useMousePosition() shares the same logic with no extra nesting — that's why hooks usually win today. Render props still shine when the shared thing must control rendering (e.g. a virtualized list deciding which rows to draw) or in libraries supporting class components. Watch for "wrapper hell" when you nest several.
These lines build a Toggle component that uses a children-as-function. Put them in the right order:
'} instead of a function child. Pass {' '} . Rendering nothing. — Your render function forgot to return the JSX. Make sure it returns an element. Wrapper hell. — Deeply nested render props are unreadable. If you only need shared logic, switch to a custom hook. New function every render hurting memoized children. — The inline function changes identity each render. Pull it out or accept the trade-off; often a hook is cleaner. 📋 Quick Reference Form Shape Named render prop {' '} Children as function {' '} Inside the component Modern alternative 🧠 Quick Recall 1. What type of value is a render prop?
A function that returns JSX. The component calls it with its data and renders the result.
You pass a function as children , and the component calls children(data) — the idiomatic render-prop form.
3. Why do hooks usually replace render props?
A custom hook shares the same logic without extra nesting or wrapper hell, keeping the JSX flat.
Build a Counter that owns its count and an increment function, then hands them to a render function the caller supplies. Run it and check your output.
Practice quiz
What is a render prop?
- A prop that holds a string of HTML
- A built-in React hook
- A prop whose value is a function that returns JSX
- A CSS property
Answer: A prop whose value is a function that returns JSX. A render prop is a function-valued prop the component calls with its data to produce the UI.
Who decides the markup when using a render prop?
- The parent, via the function it passes in
- The component that owns the logic
- React automatically
- The render prop never affects markup
Answer: The parent, via the function it passes in. The component owns the state/behavior, but the parent's render function decides what to render.
What is the idiomatic 'children as a function' form?
- <Mouse><p/></Mouse>
- <Mouse render />
- useMouse()
- <Mouse>{(data) => <p>{data.x}</p>}</Mouse>
Answer: <Mouse>{(data) => <p>{data.x}</p>}</Mouse>. You pass a function as children, and the component calls children(data).
Inside a render-prop component, how is the function invoked?
- return children;
- return children(data);
- return <children />;
- return render;
Answer: return children(data);. The component calls the function with its data, e.g. return children(pos).
What mainly replaces render props in modern React for sharing logic?
- Custom hooks
- Higher-order components
- Context only
- Class components
Answer: Custom hooks. A custom hook shares the same logic with no extra nesting, so hooks usually win today.
What is 'wrapper hell' in the render-props pattern?
- Too many props on one component
- A memory leak
- Deeply nested, pyramid-shaped JSX from nesting several render-prop components
- An infinite render loop
Answer: Deeply nested, pyramid-shaped JSX from nesting several render-prop components. Nesting multiple render-prop components produces hard-to-read, deeply indented JSX; hooks flatten it.
When are render props still a good fit?
- For all new code
- When the shared thing must control rendering, or in libraries targeting class components
- Never
- Only for styling
Answer: When the shared thing must control rendering, or in libraries targeting class components. They shine when the shared logic must control what's rendered (e.g. a virtualized list deciding rows).
Why does '<Mouse><p/></Mouse>' throw 'children is not a function'?
- Mouse is missing a key
- p is not a valid tag
- Mouse needs a ref
- children must be a function, but a JSX element was passed
Answer: children must be a function, but a JSX element was passed. The component calls children(data); passing an element instead of a function breaks that call.
If a render-prop component renders nothing, a likely cause is…
- The component is memoized
- The function returned undefined (forgot to return JSX)
- Too many props
- Missing a key
Answer: The function returned undefined (forgot to return JSX). If your render function forgets to return the JSX, nothing renders.
A downside of passing an inline render function each render is…
- It can't access data
- It throws an error
- Its identity changes every render, which can hurt memoized children
- It disables state
Answer: Its identity changes every render, which can hurt memoized children. A new inline function each render changes identity; pull it out or accept the trade-off (often a hook is cleaner).