Reputation: 143
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.
Upvotes: 1
Views: 102
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