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).