Problem Statement
Build an image carousel that shows one image at a time, with previous and next buttons and auto play.
Functional Requirements
- Navigation: The left button shows the previous image and the right button shows the next one.
- Wrap around: Next on the last image goes to the first. Previous on the first image goes to the last.
- Auto play: The carousel moves to the next image every 1 second.
- Pause on hover: Auto play stops while the mouse is over the carousel and starts again when it leaves.
Technical Constraints
- Read the images from a local
data.jsonfile and showdownload_urlfor the current index. - Keep the interval ID in a
useRefand clear it on unmount, on hover, and before starting a new one.
1. Function Explanations and useRef Usage
Main Functions
const handleNext = () => {
setIndex((prevIndex) => {
if (prevIndex === data.length - 1) {
return 0;
}
return prevIndex + 1;
});
};
const handlePrev = () => {
if (index === 0) {
setIndex(data.length - 1);
} else {
setIndex(index - 1);
}
};These functions handle carousel navigation:
handleNext: Moves to the next image, loops back to the start when at the end.handlePrev: Moves to the previous image, loops to the end when at the start.
useRef Usage
const ref = useRef(null);useRef is used here to:
- Store the interval ID returned by
setInterval. - Persist between renders without causing re-renders.
- Allow access to the interval ID for cleanup in
useEffectand mouse events.
2. prevIndex Usage
The prevIndex in handleNext is crucial because:
setIndex((prevIndex) => {
// code
});- It ensures we're working with the most current state value.
- Prevents race conditions in asynchronous updates.
- More reliable than using the
indexdirectly in the closure.
3. Commented Code Issue
The commented code:
// if (index == data.length - 1) {
// setIndex(0);
// } else {
// setIndex(index + 1);
// }This wouldn't work properly because:
- It uses the
indexfrom closure which might be stale. - State updates in React are asynchronous.
- Multiple rapid clicks could lead to incorrect index calculations.
- The functional update pattern (using
prevIndex) is more reliable.
4. Mouse Event Handlers
onMouseEnter={() => clearInterval(ref.current)}
onMouseLeave={() => {
clearInterval(ref.current);
ref.current = setInterval(handleNext, 1000);
}}These handlers provide user interaction features:
onMouseEnter: Pauses automatic sliding when the user hovers.onMouseLeave: Resumes automatic sliding when the user stops hovering.- Improves user experience by preventing slides from changing while the user is interacting.
Key Points to Remember
-
State Management
- Using
useStatefor tracking the current image index. - Functional updates for reliable state changes.
- Using
-
useRef Benefits
- Persists values between renders.
- Doesn't cause re-renders when values change.
- Perfect for storing interval IDs.
-
Cleanup
useEffectcleanup function prevents memory leaks.- Clears interval when the component unmounts.
-
Auto-sliding
- Implemented using
setInterval. - Can be paused and resumed with mouse events.
- Implemented using