Questions
These components duplicate logic. Refactor them using the Render Props pattern.
You’re working on a React application where you need to track the mouse position on the screen. You have two components: MousePositionLogger (which displays the coordinates) and MouseEmojiTracker (which displays an emoji at the mouse position).
Both components currently implement their own mouse tracking logic, including adding and removing event listeners and managing x and y state. This leads to duplicated code and makes it harder to maintain or add new components that also need mouse position.
Your task is to refactor these components. Create a single MouseTracker component that encapsulates the mouse tracking logic. Use the Render Props pattern to share the mouse position (x, y) with its children.
After refactoring, MousePositionLogger and MouseEmojiTracker should become simpler, purely presentational components that receive the mouse coordinates as props from the MouseTracker.
import React, { useState, useEffect } from 'react';
// Component 1: Duplicates mouse tracking logic
function MousePositionLogger() {
const [x, setX] = useState(0);
const [y, setY] = useState(0);
const handleMouseMove = (event) => {
setX(event.clientX);
setY(event.clientY);
};
useEffect(() => {
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, []);
return (
<div style={{ border: '1px solid blue', padding: '20px', margin: '10px' }}>
<h2>Mouse Position Logger</h2>
<p>X: {x}, Y: {y}</p>
</div>
);
}
// Component 2: Duplicates mouse tracking logic
function MouseEmojiTracker() {
const [x, setX] = useState(0);
const [y, setY] = useState(0);
const handleMouseMove = (event) => {
setX(event.clientX);
setY(event.clientY);
};
useEffect(() => {
window.addEventListener('mousemove', handleMouseMove);
return () => {
window.removeEventListener('mousemove', handleMouseMove);
};
}, []);
return (
<div style={{
position: 'absolute',
left: x,
top: y,
fontSize: '30px',
pointerEvents: 'none', // So it doesn't interfere with mouse events
}}>
🐭
</div>
);
}
export default function App() {
return (
<div style={{ height: '100vh', position: 'relative' }}>
<MousePositionLogger />
<MouseEmojiTracker />
<p style={{ position: 'absolute', bottom: '10px', left: '10px' }}>
Move your mouse around!
</p>
</div>
);
} How Different Experience Levels Approach This
import React, { useState, useEffect } from 'react'; // Component 1: Duplicates mouse tracking logic function MousePositionLogger() { const [x, setX] = useState(0); const [y, setY] = useState(0); const handleMouseMove = (event) => { setX(event.clientX); setY(event.clientY); }; useEffect(() => { window.addEventListener('mousemove', handleMouseMove); return () => { window.removeEventListener('mousemove', handleMouseMove); }; }, []); return ( <div style={{ border: '1px solid blue', padding: '20px', margin: '10px' }}> <h2>Mouse Position Logger</h2> <p>X: {x}, Y: {y}</p> </div> ); } // Component 2: Duplicates mouse tracking logic function MouseEmojiTracker() { const [x, setX] = useState(0); const [y, setY] = useState(0); const handleMouseMove = (event) => { setX(event.clientX); setY(event.clientY); }; useEffect(() => { window.addEventListener('mousemove', handleMouseMove); return () => { window.removeEventListener('mousemove', handleMouseMove); }; }, []); return ( <div style={{ position: 'absolute', left: x, top: y, fontSize: '30px', pointerEvents: 'none', }}> 🐭 </div> ); } export default function App() { return ( <div style={{ height: '100vh', position: 'relative' }}> <MousePositionLogger /> <MouseEmojiTracker /> <p style={{ position: 'absolute', bottom: '10px', left: '10px' }}> Move your mouse around! </p> </div> ); }
import React, { useState, useEffect } from 'react'; // The MouseTracker component using the Render Props pattern class MouseTracker extends React.Component { state = { x: 0, y: 0 }; handleMouseMove = (event) => { this.setState({ x: event.clientX, y: event.clientY, }); }; componentDidMount() { window.addEventListener('mousemove', this.handleMouseMove); } componentWillUnmount() { window.removeEventListener('mousemove', this.handleMouseMove); } render() { // The render prop is a function that receives the state (x, y) // and returns the JSX to be rendered. return this.props.render(this.state); } } // Refactored MousePositionLogger - now purely presentational function MousePositionLogger({ x, y }) { return ( <div style={{ border: '1px solid blue', padding: '20px', margin: '10px' }}> <h2>Mouse Position Logger</h2> <p>X: {x}, Y: {y}</p> </div> ); } // Refactored MouseEmojiTracker - now purely presentational function MouseEmojiTracker({ x, y }) { return ( <div style={{ position: 'absolute', left: x, top: y, fontSize: '30px', pointerEvents: 'none', }}> 🐭 </div> ); } export default function App() { return ( <div style={{ height: '100vh', position: 'relative' }}> {/* Use MouseTracker with a render prop for MousePositionLogger */} <MouseTracker render={({ x, y }) => ( <MousePositionLogger x={x} y={y} /> )} /> {/* Use MouseTracker with a render prop for MouseEmojiTracker */} <MouseTracker render={({ x, y }) => ( <MouseEmojiTracker x={x} y={y} /> )} /> <p style={{ position: 'absolute', bottom: '10px', left: '10px' }}> Move your mouse around! </p> </div> ); }
- Context over facts: Explains when and why, not just what
- Real examples: Provides specific use cases from production experience
- Trade-offs: Acknowledges pros, cons, and decision factors
Practice Question
What is the primary purpose of the Render Props pattern in React?