Learn how to use Render Props in React to share complex logic across your application while keeping your UI components decoupled, flexible, and highly reusable.
Previously in this course, we explored Designing Compound Components: Advanced React Architecture Patterns to manage implicit state within a shared interface. While compound components are excellent for structural cohesion, sometimes you need to share pure behavioral logic without imposing a specific DOM structure. This is where the Render Props pattern shines.
In React, the "Render Props" pattern refers to a technique where a component receives a function as a child (or a specific prop) that returns a React element. Instead of the component deciding what to render, it delegates that responsibility to the consumer, while providing the consumer with the state or logic it needs.
Think of it as an "Inversion of Control" mechanism. The component acts as a stateful "engine"—handling events, data fetching, or timers—and passes the engine's output to the function provided by the parent.
Let’s build a component that tracks mouse coordinates. We want to reuse this logic in different parts of our dashboard without locking the UI into a specific <div> or layout.
JSX// MouseTracker.js import { useState } from CE9178">'react'; const MouseTracker = ({ children }) => { const [coords, setCoords] = useState({ x: 0, y: 0 }); const handleMouseMove = (event) => { setCoords({ x: event.clientX, y: event.clientY }); }; // We call the function passed in CE9178">'children' with our state return ( <div onMouseMove={handleMouseMove} style={{ height: CE9178">'100vh' }}> {children(coords)} </div> ); }; // Usage const App = () => ( <MouseTracker> {(coords) => ( <h1> Mouse is at {coords.x}, {coords.y} </h1> )} </MouseTracker> );
In this example, MouseTracker doesn't know what the UI looks like; it only knows how to track the mouse. This allows us to swap the <h1> for a custom tooltip, a graph, or any other component without touching the tracker logic.
When you build these patterns, you must be intentional about what you expose. Over-exposing internal state can lead to tight coupling, making it harder to refactor the logic later.
As we discussed in State Colocation Strategies: Optimizing React Component Architecture, keeping state close to where it's used is vital. With Render Props, you are essentially "lifting" the state into the wrapper component.
| Feature | Render Props | Custom Hooks |
|---|---|---|
| Logic Reuse | Excellent | Excellent |
| UI Flexibility | High | High |
| Readability | Can lead to nesting ("Wrapper Hell") | Flatter component tree |
| Best For | Complex UI injection logic | Standard logic/data extraction |
While hooks have largely replaced render props for data fetching (e.g., useSWR), render props remain superior when the shared logic must return a specific UI wrapper (like an event listener container) or when you want to provide a declarative API for complex components.
Refactor the following snippet. Currently, the Toggle component is hardcoded to render a button. Change it into a Render Prop component so the user can decide whether to render a checkbox, a custom switch, or a simple text link.
Initial Code:
JSXconst Toggle = () => { const [on, setOn] = useState(false); return ( <button onClick={() => setOn(!on)}> {on ? "ON" : "OFF"} </button> ); }
Goal: Create a version that allows usage like:
JSX<Toggle> {(on, toggle) => <input type="checkbox" checked={on} onChange={toggle} />} </Toggle>
useCallback for the render function if you are passing it to a React.memo wrapped component.any types when accessing the shared state.Render Props provide a powerful way to share logic while maintaining structural flexibility. By inverting control, you allow consumers to define the UI while your component manages the stateful behavior. Use them when you need to provide a reusable container with specific lifecycle or event-handling behavior that isn't easily achieved through simple composition.
Up next: We will dive into Implementing Control Props, where we'll learn how to synchronize internal component state with external props for creating truly professional-grade UI primitives.
Master Compound Components in React to build flexible, intuitive UI APIs. Learn to share implicit state and enforce structure without the mess of prop drilling.
Read moreMaster State Colocation to stop unnecessary re-renders. Learn to move state as close as possible to its consumption point for high-performance React apps.
The Render Props Pattern
Final Project Audit & Optimization
Advanced Hook Patterns
Managing Global State with Zustand/Redux
Testing Performance-Critical Components
Static Site Generation (SSG) Patterns
Internationalization (i18n) Architecture
Accessibility (a11y) in Advanced Components
Managing Third-Party Integrations
Advanced Form Handling
Using Portals for UI Overlays
Implementing Virtualized Lists
Building Design System Primitives
Managing Large-Scale Data Fetching
Micro-Frontends with React
Security Best Practices in React
Advanced Ref Usage
Memoization Pitfalls
Mastering React Patterns for Scalability
Advanced TypeScript with React