Skip to content

Image Carousel

Cycle through images with previous and next buttons, wrap around at both ends, and auto-advance on a timer that pauses on hover.

Stage 4intro2 min read

Problem Statement

Build an image carousel that shows one image at a time, with previous and next buttons and auto play.

Functional Requirements

  1. Navigation: The left button shows the previous image and the right button shows the next one.
  2. Wrap around: Next on the last image goes to the first. Previous on the first image goes to the last.
  3. Auto play: The carousel moves to the next image every 1 second.
  4. 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.json file and show download_url for the current index.
  • Keep the interval ID in a useRef and 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 useEffect and 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 index directly 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 index from 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

  1. State Management

    • Using useState for tracking the current image index.
    • Functional updates for reliable state changes.
  2. useRef Benefits

    • Persists values between renders.
    • Doesn't cause re-renders when values change.
    • Perfect for storing interval IDs.
  3. Cleanup

    • useEffect cleanup function prevents memory leaks.
    • Clears interval when the component unmounts.
  4. Auto-sliding

    • Implemented using setInterval.
    • Can be paused and resumed with mouse events.

In this topic

Done with this topic?

How well do you know it?

PreviousModal