Tahir Musharraf
Tahir Musharraf

Reputation: 143

Does React rendering effects the setTimeout or setInterval function wrapped in a useRef and useRef is good way to achieve pause, stop, update question

I'm trying to achieve the slider functionality, where I want to slider to move to the next question after every three seconds [this part is working fine]

Features i'm trying to achieve:

The issue is when I changed the question_number by onClick event, the next question start showing after every 1 seconds instead of 3 seconds. I think the problem is somehow with the React Re-rendering.

setSlider is simple useState has object:

const [timeSlider, setTimeSlider] = useState({
  question_length: 4,
  question_number: 0,
  current_time: 0
});

I'm using useEffect to check the viewport width so react Re-render the components everytime, Viewport changes

I tried to store the Interval for timer in a react useRef. but still not working. Here is my code:

I use useRef, so I can Resume, Pause and updateNumber outSide where the first time setInterval started const interval = useRef(null);

After EverySecond update the useState: Seconds

useEffect(() => {
  setRemaining({
    start_time: Date.now(),
    stop_time: 0
  });
  interval.current = setInterval(() => {
    setSeconds(seconds => seconds + 1);
  }, 1000);
  pauseSlider();
  return () => clearInterval(interval);
}, []);

And when ever the seconds state changed, I make sure after every three seconds. question_number increased only when its less than 3

useEffect(() => {
  if (seconds === 3) {
    setSeconds(seconds => 0);
    setTimeSlider(prev => prev.question_number === 3 ? { ...timeSlider,
      question_number: 0
    } : { ...timeSlider,
      question_number: timeSlider.question_number + 1
    });
  }
}, [seconds]);

Below are the pause, resume and update function.

function pauseSlider() {
  setSliderHover(true)
  setRemaining({
    start_time: 0,
    stop_time: Date.now()
  });
  clearInterval(interval.current);
}

function resumeSlider() {
  setSliderHover(false)
  setRemaining(prev => ({ ...prev,
    start_time: prev.stop_time,
    stop_time: 0
  }));
  interval.current = setInterval(() => {
    setSeconds(seconds => seconds + 1);
  }, 1000);
}

function updateNumber(num) {
  setSliderHover(false)
  setSeconds(0)
  setRemaining({
    start_time: 0,
    stop_time: 0
  });
  clearInterval(interval.current);
  interval.current = setInterval(() => {
    setSeconds(seconds => seconds + 1);
  }, 1000);
  setTimeSlider({ ...timeSlider,
    question_number: num
  });
}

The Problem could be in these functions, I tried to use setTimeout instead of setInterval same results.

Below is the picture of slider, so you have more clear idea what i'm trying to achieve.

Demo of what i'm trying to achieve, the current question_number is 3 (questions starts from 0)

Upvotes: 1

Views: 102

Answers (1)

Tahir Musharraf
Tahir Musharraf

Reputation: 143

Instead of using the JS, I used the GSAP for this here is my solution for it

useLayoutEffect(() => {
    const ctx = gsap.context((self) => {
      TimelineRef.current = gsap.timeline({
        defaults: {
          repeat: -1,
          ease: "none",
        }
      })
        
      .to(".timerSlier_left", 
      {
        x: "0%",
        duration: 10,
        onRepeat: () => UpdateToNextQuestion(timeSlider),

      }
      )
    }, ContainerRef); // <- Scope!
    return () => ctx.revert(); // <- Cleanup!
  }, []);

  
  const [ remaining, setRemaining ] = useState(0);
  
  useEffect(()=>{
    if ( isInViewport ){
      resumeSlider()
    }else{
      pauseSlider()
    }
  }, [ isInViewport ]);
  const UpdateToNextQuestion = () => {
    settimeSlider( prev => prev.question_number === 3 ? ({...prev, question_number: 0}) : ({...prev, question_number: prev.question_number+1}))
  }

  function pauseSlider(){
    console.log("stop slider")
    setSliderHover(true)
    TimelineRef.current.pause();
  }
  function resumeSlider(){
    setSliderHover(false)
    TimelineRef.current.resume();
  }
  function updateNumber(num){
    TimelineRef.current.restart();
    settimeSlider( timeSlider => ({ ...timeSlider, question_number: num }) );
    console.log("RESUMING")
    setSliderHover(false)
    TimelineRef.current.resume();
  }

I'm handing timeout functionality from GSAP timeline.

Upvotes: 0

Related Questions