6

In my SPA made with VUE I have a component running a recursive few of setInterval functions (it's a countdown). I noticed the countdown continue in the background when I switch view to another component, but I prefer to destroy the setInterval.

I tried using a global data having the countdowns and then destroy it on destroyed hook but it doesn't work.

Here my code:

    data: function () {
        return {
            counters: ""
        }
    }),

   methods: {
     countdown(index, exp) {
        ...
          this.counters = setInterva()
        ...
        },
   },

   destroyed(){
        console.log(this.counters); // returns a progressive integer
        clearInterval(this.counters);
        console.log(this.counters); // returns same integer
        this.counters = 0;
        console.log("destroyed");
    } 

But in the console I got:

destroyed

app.js:64433 0

app.js:64398 Missing counter_1 . <--- which means counter is still running

Thanks for any suggestion!

Community
  • 1
  • 1
Uncoke
  • 1,832
  • 4
  • 26
  • 58
  • Put your destroyed function adjacent to methods. not inside methods. – Socrates Tuas Aug 23 '19 at 07:51
  • Yes, it is. Just fixed the typo in the post. – Uncoke Aug 23 '19 at 07:54
  • 1
    Can you share the entire code of the coundown method? I wonder if `this` when you use it inside of the method might actually not refer to the vue instance (a context problem?) so that when you reference it in the destroyed hook it might not be assigned to that variable. Have you tried to console log `this.counters` in the destroyed hook? Is it defined? – Tobias G. Aug 23 '19 at 08:02
  • @TobiasG. The countdown method contains only the setInterval function. I have tried to log the this.counters value in the last hook before and after the clearInterval: it it an integer (progressive) before and same value after clearInterval. – Uncoke Aug 23 '19 at 08:45
  • 2
    Please share all your component code. I think the issue can be you call countdown multiple times and you just cleanup the last. If that is correct, you should convert counters to an array of task ids to clean up and then clean in a loop. Or protect the invocation of the setInterval cleanup the last scheduled task before starting a new one. – Mario Santini Aug 23 '19 at 09:03
  • Maybe a solution could be here: https://stackoverflow.com/questions/19970399/how-do-i-kill-a-setinterval-settimout-if-i-lose-the-calling-object – Uncoke Aug 23 '19 at 09:03
  • What @MarioSantini said, i just entered your code above into jsfiddle and could not find any issue why it wouldn't work, so i think it's very likely that your problem is in an area of your code that you did not share yet. – Tobias G. Aug 23 '19 at 09:08

5 Answers5

5

There might be two things happening here depending on if you are calling countdown or not:

1. countdown is not called

countdown(index, exp) needs to be defined in the created hook such as below. Furthermore, a method foo() should be bound to this interval for the expected functionality.

  created: function(){
      this.counterInterval =  setInterval(
        function()
        {
          this.foo();
        }.bind(this), 500);
    return this.foo();
  },
  destoyed: function(){
    clearInterval( this.counterInterval )
  },

2. countdown is called properly but the component is actually not getting destroyed

If the error is actually a misunderstanding on what it means to "destroy" the component, such that the component is not getting destroyed, the same code as above can be used, but a data prop of isShowing: true bounded within the JSX will solve the problems.

Just do a v-if check on isShowing and then do an event listener if the element is in view. If the element is in view, then we have isShowing===true. else, false.

T.Woody
  • 1,142
  • 2
  • 11
  • 25
4

In vue3 destroy() and beforeDestroy() has been deprecated.

Use unmount() or beforeUnmount() instead.

beforeUnmount(){
    clearInterval(this.counters);
}
Zagrios
  • 51
  • 1
  • 5
1

You should use beforeDestroy hook instead of destroyed

For reference on vue lifecycle check out https://v2.vuejs.org/v2/guide/instance.html#Lifecycle-Diagram

tony19
  • 125,647
  • 18
  • 229
  • 307
Hendry
  • 882
  • 1
  • 11
  • 27
  • 1
    the `destroyed` hook still has access to `this`of the instance so this should not be the problem. See here: https://jsfiddle.net/tbgse/ck5zw4mu/2/ – Tobias G. Aug 23 '19 at 10:29
  • Learn something new every day, Thanks! @TobiasG. – Hendry Aug 26 '19 at 12:52
0

Try this Change destroyed() method to beforeDestroy().

update

maybe vue component did not destroy. try destroy manually

sorry for my bad English

saleh shokouhi
  • 445
  • 4
  • 7
  • the `destroyed` hook still has access to `this`of the instance so this should not be the problem. See here: https://jsfiddle.net/tbgse/ck5zw4mu/2/ – Tobias G. Aug 23 '19 at 10:29
0

Use beforeRouteLeave route navigation guard inside route components to destroy setInterval. Add clearInterval function inside beforeRouteLeave, this will destroy the timer set by setInterval before we leave the component

beforeRouteLeave (to, from, next) {
    clearInterval(this.counters);
    next()
},
Slava Rozhnev
  • 9,510
  • 6
  • 23
  • 39