How to Implement Render Props in React
Render props is a powerful pattern in React used for sharing stateful logic between components using a prop whose value is a function. This article provides a clear, step-by-step guide on how to implement the render props pattern in React, complete with a practical code example to help you understand how to share behavior dynamically across your application.
Understanding the Render Props Pattern
In React, the render props pattern involves passing a function as a prop to a component. This function tells the component what to render. Instead of a component nesting hardcoded UI, it focuses purely on state management or behavioral logic, delegates the UI rendering to the consumer, and passes its internal state as arguments to the rendering function.
This pattern is highly effective for separation of concerns, allowing you to reuse stateful behavior (like tracking mouse coordinates, fetching data, or handling form states) across different presentation components.
Step-by-Step Implementation
Let’s build a practical example: a reusable MouseTracker
component that tracks the mouse position on the screen and shares that
coordinate state with any presentation component.
Step 1: Create the Logic Component (The Provider)
First, create a component that manages the state and event listeners.
Instead of rendering a specific UI, this component will call a prop
(usually named render) and pass the state to it.
import { useState, useEffect } from 'react';
const MouseTracker = ({ render }) => {
const [coords, setCoords] = useState({ x: 0, y: 0 });
useEffect(() => {
const handleMouseMove = (event) => {
setCoords({
x: event.clientX,
y: event.clientY,
});
};
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, []);
// Call the render prop function and pass the state as an argument
return render(coords);
};
export default MouseTracker;Step 2: Consume the Logic Component (The Presenter)
Now, you can use the MouseTracker component anywhere in
your application. You pass a function to the render prop,
which receives the mouse coordinates and returns the JSX you want to
display.
import React from 'react';
import MouseTracker from './MouseTracker';
const App = () => {
return (
<div style={{ height: '100vh', padding: '20px' }}>
<h1>Move your mouse around!</h1>
{/* Implementing the render prop */}
<MouseTracker
render={(coords) => (
<p>The current mouse position is ({coords.x}, {coords.y})</p>
)}
/>
</div>
);
};
export default App;In this implementation, MouseTracker handles the event
listener lifecycle and state management, while App decides
exactly how to display those coordinates.
Using the Children Prop as a Render Prop
You do not have to name the prop render. A common
alternative is using React’s default children prop. This
allows for a cleaner syntax when nesting components.
Implementation with Children:
Modify the logic component to return children instead of
render:
const MouseTracker = ({ children }) => {
// ... state and hook logic remain the same ...
return children(coords);
};Usage:
When consuming the component, pass the rendering function inside the component tags:
<MouseTracker>
{(coords) => (
<p>Mouse is at: {coords.x}, {coords.y}</p>
)}
</MouseTracker>Key Benefits of Render Props
- Code Reusability: You can reuse the exact same stateful logic with entirely different visual UI outputs without duplicating code.
- Decoupled Concerns: It cleanly separates state management and event handling from UI presentation.
- Explicit Data Flow: Unlike Mixins or older HOC (Higher-Order Component) patterns, it is clear where the state comes from, avoiding namespace clashes.