I have four screens A (HomePage), B, C, D
Each of screens have a function that will be triggered when the screen onStart
or onResume
, I achieve it by react-redux.
countdownToFirstScreen = () => {
this.timeOut = setTimeout(()=> {
clearTimeout(this.timeOut); // clearTimeout before navigate next screen
this.props.leaveTheScreenTime(); // change for some redux store boolean
this.props.navigation.navigate('A');
}, 9000);
}
If user click <Button />
before countdown finish, I set the clearTimeout too.
<Button
onPress={() => {
clearTimeout(this.timeOut);
this.props.navigation.navigate('nextScreen');
}
/>
It is working when I just navigate between A and B and C.
My issue happens when I try to navigate from C to D.
C screen function countdownToFirstScreen
will be triggered eventhough I click the <Button />
on C screen.
Any one knows what happened with my setTimeout
and clearTimeout
?
To clear a timeout or an interval in React with hooks: Use the useEffect hook to set up the timeout or interval. Return a function from the useEffect hook. Use the clearTimeout() or clearInterval() methods to remove the timeout when the component unmounts.
The clearTimeout function will be called before the component is unmounted. But the timer is in an async function, and it starts again after I got response from server.
You don't actually need to use clearTimeout , you only use it if you wish to cancel the timeout you already set before it happens. It's usually more practical to use clearInterval with setInterval because setInterval usually runs indefinitely.
To cancel a setTimeout() method from running, you need to use the clearTimeout() method, passing the ID value returned when you call the setTimeout() method.
It looks like you may run into scoping issues as this
in the setTimeout
callback may have a different context than this.timeOut
and thus the timer is not being cleared. Ideally you want a setup where you track the timer in some global component like your AppComponent
which is on every screen, with a setup like:
componentWillMount () {
// Add your listener
DeviceEventEmitter.addListener('timer', this.clearTimer.bind(this));
}
componentDidMount () {
startTimer()
}
componentWillUnMount () {
clearTimer()
}
startTimer () {
this.timer = this.setTimeout(() => {
this.props.navigation.navigate('A');
},9000);
clearTimer () {
// Handle an undefined timer rather than null
this.timer !== undefined ? this.clearTimeout(this.timer) : null;
}
Using React-Hooks and Functional Components ... things are alot easier...
An effect with empty-deps []
simulates componentDidMount
, and its cleanUp-callback simulates componentWillUnmount
const timerRef = useRef(null);
useEffect(() => {
timerRef.current = setTimeout(() => {
/** Your logic goes here */
}, 9000);
return () => {
if (timerRef.current) {
clearTimeout(timerRef.current);
}
};
}, []);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With