skip to Main Content

I created a slideshow in the Nextjs project, But I have a bug. When the user clicks on a link and the page has changed I get an Unhandled Runtime Error and I know it because of the setTimeout function it calls a function and tries to style an element that does not exist on the new page.
How can I clear the setTimeout function after the user click the links?

Error screenshot:

enter image description here

My component code:

import { useEffect, useState } from "react";
import SlideContent from "./slide-content";
import SlideDots from "./slide-dots";
import SlideItem from "./slide-item";

const Slide = (props) => {
  const { slides } = props;
  const [slideLength, setSlideLength] = useState(slides ? slides.length : 0);
  const [slideCounter, setSlideCounter] = useState(1);

  const handleSlideShow = () => {
    if (slideCounter < slideLength) {
      document.querySelector(
        `.slide-content:nth-of-type(${slideCounter})`
      ).style.left = "100%";
      const setSlide = slideCounter + 1;
      setSlideCounter(setSlide);

      setTimeout(() => {
        document.querySelector(
          `.slide-content:nth-of-type(${setSlide})`
        ).style.left = 0;
      }, 250);
    } else {
      document.querySelector(
        `.slide-content:nth-of-type(${slideCounter})`
      ).style.left = "100%";
      setSlideCounter(1);
      setTimeout(() => {
        document.querySelector(`.slide-content:nth-of-type(1)`).style.left = 0;
      }, 250);
    }
  };

  useEffect(() => {
    if (slideLength > 0) {
      setTimeout(() => {
        handleSlideShow();
      }, 5000);
    }
  }, [slideCounter, setSlideCounter]);

  return (
    <>
      <div className="slide-button-arrow slide-next">
        <span className="carousel-control-prev-icon"></span>
      </div>
      <div className="slide">
        {slides.map((slide) => (
          <SlideContent key={`slide-${slide.id}`}>
            <SlideItem img={slide.img} title={slide.title} />
          </SlideContent>
        ))}
        <SlideDots activeDot={slideCounter} totalDots={slides} />
      </div>
      <div className="slide-button-arrow slide-prev">
        <span className="carousel-control-next-icon"></span>
      </div>
    </>
  );
};

export default Slide;

I use my slideshow component inside the home page file.

2

Answers


  1. useEffect(() => {
    
        let timer;
        if (slideLength > 0) {
          timer=setTimeout(() => {
            handleSlideShow();
          }, 5000);
        }
    
        return () => {
          clearTimeout(timer);
        };
      }, [slideCounter, setSlideCounter]);
    
    Login or Signup to reply.
  2. you should remove your timeout function when the component unmounts.
    (if you’re using old syntax there is componentWillUnmount() function)
    when you are using hooks you can return your useEffect so it will cause the unmount function.
    in your case it will be something like this:

    useEffect(() => {
        //define a temp for your timeout to clear it later
        let myTimeout;
        if (slideLength > 0) {
          //assign timeout function to the variable
          myTimeout = setTimeout(() => {
            handleSlideShow();
          }, 5000);
        }
        // this triggers when the component unmounts or gets re-rendered.
        // you can clear the timeout here.
        return () => {
            clearTimeout(myTimeout);
        }
      }, [slideCounter, setSlideCounter]);
    

    you should always remove your timeouts because you don’t want memory leaks and performance issues. it might not give you errors but clear them all.

    there is an old post i guess you can read here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search