A Render Prop is a pattern for sharing code between React components using a function that returns a React element.
A component that uses a render prop expects a function as a prop, and this function returns a React element.
Render Prop Pattern Example
const MyComponent = ({ render }) => { return ( <div> {render("Hello from render prop!")} </div> ); }; const App = () => { return ( <MyComponent render={(message) => <h1>{message}</h1>} /> ); }; export default App;
In this example:
MyComponent
accepts arender
prop, which is a function.- This function is invoked with the message
"Hello from render prop!"
, and the resulting<h1>
element is rendered inside theMyComponent
.
1. Why Use Render Props?
Render props are a pattern used to:
- Share functionality: Reuse logic across components by passing a function to define the rendering.
- Customizable UI: Allow the consumer component to define how things should look by controlling what gets rendered.
- Flexibility: Enable passing props and logic between components without directly modifying the child component.
2. Practical Example of Render Props
A. Mouse Tracker Example
Let’s say you want to track mouse position in a component and share that logic across multiple components.
Step 1: Create a Mouse Tracker Component
import React, { Component } from "react"; class MouseTracker extends Component { state = { x: 0, y: 0, }; handleMouseMove = (event) => { this.setState({ x: event.clientX, y: event.clientY, }); }; render() { return ( <div style={{ height: "100vh", border: "1px solid black" }} onMouseMove={this.handleMouseMove} > {this.props.render(this.state)} {/* Render prop is called here */} </div> ); } } export default MouseTracker;
Step 2: Use Mouse Tracker in Another Component
import React from "react"; import MouseTracker from "./MouseTracker"; const App = () => { return ( <MouseTracker render={({ x, y }) => ( <h1> Mouse position: ({x}, {y}) </h1> )} /> ); }; export default App;
What happens?
MouseTracker
tracks mouse movement and updates thex
andy
coordinates.- The
App
component receives the render prop and renders the coordinates within an<h1>
tag. - This pattern allows any parent component to define how mouse position should be displayed.
3. When to Use Render Props?
You might want to use render props when:
- You have shared logic that you want to inject into multiple components without changing the component structure.
- You need customized rendering in child components.
- You need to pass state or callbacks down to child components that control rendering.
4. Avoiding Prop Drilling with Render Props
In deep component trees, prop drilling (passing props from parent to deeply nested children) can be cumbersome. Render props can help avoid this by centralizing logic in a higher component.
Example: Using Render Prop to Avoid Prop Drilling
Let’s say you have several nested components, and you want to pass data from the top level without prop drilling.
const ParentComponent = () => { const userData = { name: "John", age: 30 }; return ( <ChildComponent render={(data) => <GrandchildComponent user={data} />} /> ); }; const ChildComponent = ({ render }) => { const data = { name: "Alice", age: 25 }; return render(data); }; const GrandchildComponent = ({ user }) => { return <div>{user.name} is {user.age} years old.</div>; };
This avoids deep prop drilling and keeps your code cleaner.
5. Performance Considerations
While render props provide flexibility, it can sometimes result in unnecessary re-renders, especially if the function passed to the render prop changes on every render. To optimize performance:
- Use
React.memo
: If the rendered output is the same and doesn’t need to change. - Use
useCallback
: To memoize the render function passed to the render prop, preventing unnecessary re-renders.