0

I'm trying to make a slideshow of 5 pictures using react hooks and a setInterval.

So when the counter comes to photo 5(index 4) it goes back to photo1(index 0).

The counter seems ok, but keeps counting when it comes to 4 even though the condition in the if statement is false.

import React, { useState, useEffect } from 'react';
import { photoSource } from './photo-source.js';

 function Slideshow() {

const [imgSource, setImgSource] = useState(0);

useEffect(() => {
  const intervalId = setInterval(() => {
          if (imgSource <= 1) {
            setImgSource(imgSource => imgSource + 1);
          } else {
            setImgSource(0);
                }
          }, 10000);
    return () => clearInterval(intervalId);
}, []);

console.log('ImgSource: ' + imgSource);
console.log(imgSource <= 1)
console.log(photoSource[imgSource].src)

All the values logged to the console seems right, the only obvious problem is that the counter keeps counting as if the if statement would not work.

skyboyer
  • 22,209
  • 7
  • 57
  • 64

1 Answers1

0

Two issues I can see here. First is pretty minor: the condition should be imgSource < 4, not imgSource <= 1. Second, and much more importantly, the value of imgSource outside of setImgSource is locked at the value it was when setInterval was called (locked at zero). Thus the condition is always true since imgSource is 0, and the value continues to increment past the target max value of 4.

There are a few ways you can handle this, the simplest of which is to perform the check within the setImgSource callback as that will have access to the current value of imgSource.

For example:

useEffect(() => {
        const intervalId = setInterval(() => {
            setImgSource((imgSource) => {
                if (imgSource < 4) {
                    return imgSource + 1;
                }
                return 0;
            });
        }, 10000);
        return () => clearInterval(intervalId);
    }, []);

Though you can cut out some code by using the % (remainder) operator, like this:

useEffect(() => {
        const intervalId = setInterval(() => {
            setImgSource((imgSource) => (imgSource + 1) % 5);
        }, 1000);
        return () => clearInterval(intervalId);
    }, []);

Note that in JavaScript, the % operator does remainder, not modulus. The two are the same for positive numbers so this approach will work since you are just incrementing imgSource. You'd have to do a bit more to make the same approach work if you want the slide show to change directions, here's a mod function:

export function mod(n, m) {
    return ((n % m) + m) % m;
}

Which you could use like this:

setImgSource(prev => mod(prev + 1, 5));
Henry Woody
  • 14,024
  • 7
  • 39
  • 56