Skip to content
Advertisement

Two-second timeout not being respected by function on NextJS site

I have an ‘image slide show’ implementation which cycles among images every two seconds. It does so by changing their display types from “none” to “block”.

At the top of my .js file, the showSlides function is defined:

var slideIndex = 0;

function showSlides() {
    if (process.browser) {
        let i;
        let slides = document.getElementsByClassName("introSlides");

        for (i = 0; i < slides.length; i++) {
            slides[i].style.display = "none";  
        }
        
        if (slideIndex >= slides.length) {
            slideIndex = 0
        }    

        //console.log("Displaying image %s/%s" % (slideIndex, slides.length))

        if (slides != null && slides[slideIndex] != null) {
            slides[slideIndex].style.display = "block";
            slideIndex++;
        }

        setTimeout(showSlides, 2000); // Change image every 2 seconds
    }
  }

From here, I create four items, and call the showSlides function from within the HTML of the Home() function, which is located within the same .js file:

                {/*Character intros image gallery*/}
                <div class="fontSizeZero">
                    <div className="introSlides fade">
                        <img src="/poster-shinji.jpg" className="fullWidthImage"></img>
                    </div>

                    <div className="introSlides fade">
                        <img src="/poster-omi.jpg" className="fullWidthImage"></img>
                    </div>

                    <div className="introSlides fade">
                        <img src="/poster-crash.jpg" className="fullWidthImage"></img>
                    </div>

                    <div className="introSlides fade">
                        <img src="/poster-stiletto.jpg" className="fullWidthImage"></img>
                    </div>
                </div>

                {/*Call the slide show function*/}
                <script>
                    {showSlides()}
                </script>

This only seems to work sometimes. Other times, the period between images is extremely rapid, to the point where I may not even see the image. It seems related to leaving the page and coming back to it.

I find the global slideIndex variable to be suspicious, but I’m not sure how else to go about implementing.

Pardon me, a first time NextJS user. Thank you for any insights.

Advertisement

Answer

It seems there were multiple instances of the Timer, causing chaos with the DOM.

Altering the definition at the top of the .js file to use Effects seems to have been a successful approach:

var slideIndex = 0;

const showSlides = setTimerId => () => {
    if (process.browser) {
        let i;
        let slides = document.getElementsByClassName("introSlides");

        for (i = 0; i < slides.length; i++) {
            slides[i].style.display = "none";  
        }
        
        if (slideIndex >= slides.length) {
            slideIndex = 0
        }    

        //console.log("Displaying image %s/%s" % (slideIndex, slides.length))

        if (slides != null && slides[slideIndex] != null) {
            slides[slideIndex].style.display = "block";
            slideIndex++;
        }

        setTimerId(setTimeout(showSlides(setTimerId), 2000));
    }
}

Within the Home function, we have a call to the Effect like so:

export default function Home() {

    const [timerId, setTimerId] = useState();
    const timerIdRef = useRef();

    timerIdRef.current = timerId;

    useEffect(() => {
        setTimerId(setTimeout(showSlides(setTimerId), 1000));
        return () => {
            clearTimeout(timerIdRef.current);
        };
    }, []);

I’ve also removed the call to showSlides() from within the JSX of the Home function.

User contributions licensed under: CC BY-SA
9 People found this is helpful
Advertisement