Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clearTimeout is not working in React Native

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?

like image 978
Morton Avatar asked Jan 28 '19 02:01

Morton


People also ask

How do I clear timeout in React native?

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.

Is clearTimeout asynchronous?

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.

Is clearTimeout necessary?

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.

How do I clear set timeout?

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.


2 Answers

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;
}
like image 165
Chad Nehemiah Avatar answered Oct 18 '22 03:10

Chad Nehemiah


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);
      }
    };
  }, []);
like image 23
Hend El-Sahli Avatar answered Oct 18 '22 02:10

Hend El-Sahli