Emil Skovmand
Emil Skovmand

Reputation: 99

Running setInterval() inside React function happens multiple times and increases the amount rapidly over time

Check the console inside this sandbox: https://codesandbox.io/s/twilight-thunder-c71ov?file=/src/App.js

function Subjects({ logoArray }) {
  const item1 = useRef();
  const item2 = useRef();
  const item3 = useRef();
  const item4 = useRef();

  const [images, setImages] = useState({ arr: logoArray, hasmoved: 0 });

  setInterval(() => {
    let randomChoice = Math.floor(Math.random() * 4);
    let randomSwitch =
      Math.floor(Math.random() * (images.arr.length - 1 - 4 + 1)) + 4;

    // Handle Randomchoice
    if (randomChoice === images.hasmoved) {
      if (images.hasmoved === 3) randomChoice--;
      else randomChoice++;
    }

    let updatedArray = images.arr;

    let changeThis = updatedArray[randomChoice];
    let switchThis = updatedArray[randomSwitch];

    updatedArray[randomChoice] = switchThis;
    updatedArray[randomSwitch] = changeThis;

    setImages({ arr: updatedArray, hasmoved: randomChoice });

    console.log("Happened");
  }, 5000);

  const handleTransition = (ev, n) => {};

  return (
    <>
      <li
        ref={item1}
        onTransitionEnd={(ev) => handleTransition(ev, item1)}
        className="bar-item"
      ></li>
      <li
        ref={item2}
        onTransitionEnd={(ev) => handleTransition(ev, item2)}
        className="bar-item"
      ></li>
      <li
        ref={item3}
        onTransitionEnd={(ev) => handleTransition(ev, item3)}
        className="bar-item"
      ></li>
      <li
        ref={item4}
        onTransitionEnd={(ev) => handleTransition(ev, item4)}
        className="bar-item"
      ></li>
    </>
  );
}

Every time "happened" is logged to the console my setInterval() function has completed, but it's only supposed to run once every five second.

Can anyone explain to me, why this happens and possibly come up with a solution?

Upvotes: 2

Views: 1208

Answers (1)

Emil Skovmand
Emil Skovmand

Reputation: 99

For anyone visiting this answer in the future... I fixed it and even added the transitionHandler, enjoy :)

function Subjects({ logoArray }) {

    const item1 = useRef();
    const item2 = useRef();
    const item3 = useRef();
    const item4 = useRef();

    const [images, setImages] = useState({ arr: logoArray })

    const dissapear = "activeOut";
    const appear = "activeIn";

    const handleTransition = (ev, item, index) => {
        if (item.current.classList.contains(dissapear)) {

            let randomSwitch = Math.floor(Math.random() * ((images.arr.length - 1) - 4 + 1)) + 4;

            let updatedArray = images.arr;

            let changeThis = updatedArray[index];
            let switchThis = updatedArray[randomSwitch];

            updatedArray[index] = switchThis;
            updatedArray[randomSwitch] = changeThis;

            setImages({ arr: updatedArray });

            item.current.classList.replace(dissapear, appear);

        } else if (item.current.classList.contains(appear)) item.current.classList.remove(appear);
    }

    useEffect(() => {
        const interval = setInterval(() => {
            let randomChoice = Math.floor(Math.random() * (Math.floor(3) - Math.ceil(0) + 1)) + Math.ceil(0);

            if (randomChoice == 0) item1.current.classList.add(dissapear);
            if (randomChoice == 1) item2.current.classList.add(dissapear);
            if (randomChoice == 2) item3.current.classList.add(dissapear);
            if (randomChoice == 3) item4.current.classList.add(dissapear);
        }, 5000);
        return () => {
            clearInterval(interval);
        };
    }, []);


    return (
        <>
            <li ref={item1} onTransitionEnd={ev => handleTransition(ev, item1, 0)} className="bar-item">
                {images.arr[0]}
            </li>
            <li ref={item2} onTransitionEnd={ev => handleTransition(ev, item2, 1)} className="bar-item">
                {images.arr[1]}
            </li>
            <li ref={item3} onTransitionEnd={ev => handleTransition(ev, item3, 2)} className="bar-item">
                {images.arr[2]}
            </li>
            <li ref={item4} onTransitionEnd={ev => handleTransition(ev, item4, 3)} className="bar-item">
                {images.arr[3]}
            </li>
        </>
    )

}

Upvotes: 4

Related Questions