I have made a basic slideshow demo where on checking the checkbox slideshow is enabled. Problem is that once enabled slide show can't be disabled even if I uncheck the checkbox. As per muy understanding, I'm learning the timer and also nullifying the state storing the timer but the slide show keep on going.
Specifically this part gets invoked on checkbox update:
useEffect(() => {
if (isTrue) {
setSlideTimer(() => {
return setInterval(() => {
forwardButton.current.click();
}, slideDuration);
});
} else {
clearInterval(slideTimer);
setSlideTimer(null);
}
}, [isTrue]);
From browser logs it is evident that timer indeed got cleared. Though there is a warning "... component is changing an uncontrolled input of type checkbox to be controlled"
but I'm not sure if that's the culprit here.
CodePudding user response:
Try this!
useEffect(() => {
let interval;
if (isChecked) {
interval = setInterval(() => {
forwardButton.current.click();
}, 1000); // change it
}
return function cleanup() {
clearInterval(interval);
console.log('Clear timer');
};
}, [isChecked]);
CodePudding user response:
Another approach is to use the setTimeout()
method. For this you would need to create a new state clicks
(or any other name) that will trigger the useEffect
every time it changes, allowing setTimeout
to work as setInterval
const [clicks, setClicks] = useState(0)
useEffect(() => {
if(isChecked){
setTimeout(() => {
forwardButton.current.click()
setClicks(clicks 1)
}, slideDuration)
}
}, [isChecked, clicks])
CodePudding user response:
Issue
The issue is that you've a missing dependency on the sliderTimer
state.
useEffect(() => {
if (isTrue) {
setSlideTimer(() => {
return setInterval(() => {
forwardButton.current.click();
}, slideDuration);
});
} else {
clearInterval(slideTimer);
setSlideTimer(null);
}
}, [isTrue]);
Solution
Don't generally store timer ids in state. Use a React ref is you need to access the timer id outside the useEffect
hook, otherwise just cache it locally within the useEffect
hook's callback. In this case you will want to use a ref to hold the sliderTimer
id value so it can also be cleared in the case the component unmounts.
Example:
const sliderTimerRef = React.useRef();
useEffect(() => {
// Clear any running intervals on component unmount
return () => clearInterval(sliderTimerRef.current);
}, []);
useEffect(() => {
if (isTrue && forwardButton.current) {
sliderTimerRef.current = setInterval(
forwardButton.current.click,
slideDuration
);
} else {
clearInterval(sliderTimerRef.current);
}
}, [isTrue]);
Additional issue
From browser logs it is evident that timer indeed got cleared. Though there is a warning
"... component is changing an uncontrolled input of type checkbox to be controlled"
but I'm not sure if that's the culprit here.
This is typically the case when the value
or checked
prop changes from an undefined to a defined value. Ensure whatever the checked state is that it is initially defined, even if just false
.