Reliable way to clear a setInterval used by a Lightning Component?

I’m using JavaScript’s setInterval to run some client code every few seconds in a Lightning Component and also have clearInterval logic working to remove that timer within the component.

But if user navigates away I also need to run the clearInterval (as otherwise my background logic continues to run when it shouldn’t) but as posts such as How do I get the Lightning Component “destroy” system event to fire? suggest, that turns out to be quite hard.

Any working patterns for this?

Answer

Usually, the component does not get destroyed once you navigate to a different view. When I tested at my end it usually takes around 9 distinct navigation(eg: visiting 9 different tabs) for the component to become invalid (i.e destroy).

In general, when component is destroyed it is necessary to remove event handler or callbacks attached to the window,document,.. objects. The right place to do it is in the unrender handler of a component as mentioned here

You could do two things:

1) Use unrender to clear the setInterval. (NOTE: Even though it does not get cleared once you navigate. Since each view has its own version of the window object (see below attachment), I think it might not be issue).

2) Listen to aura:locationChange event and clear the interval.

Below

<aura:component implements="force:appHostable,flexipage:availableForAllPageTypes">
<aura:attribute name="counter" type="Integer" default="0"/>
<aura:attribute name="setIntervalId" type="Integer"/>
<aura:handler name="init" value="{!this}" action="{!c.initMethod}" />
<aura:handler event="aura:locationChange" action="{!c.handleDestroy}"/>

    Counter : {!v.counter}
</aura:component>

controller.js

({
    initMethod : function( cmp, evt, h ) {
        var i = 0;
        var interval = window.setInterval(
            $A.getCallback(function() {

                var value = i++;
                console.log(value + ' from component with id ' + cmp.getGlobalId());
                // code to execute periodically goes here
                cmp.set("v.counter", value);

            }), 2000
        );   


        cmp.set("v.setIntervalId", interval) ;   

    },
    handleDestroy : function( cmp, evt, h ) {
        console.log('clear interval due to navigation');
        window.clearInterval(cmp.get("v.setIntervalId"));
    },
})

renderer.js

({
    // Your renderer method overrides go here
    unrender: function (cmp,helper) {
        this.superUnrender();
        console.log('clear interval due to unrender');

        window.clearInterval(cmp.get("v.setIntervalId"));
    }
})

An interesting note, when I added the above component to two tabs in LEX; each component’s setTimeout logs separately without overriding each other. Looks like Lightning creates window instance for a view in LEX.

enter image description here

Attribution
Source : Link , Question Author : Keith C , Answer Author : Praveen

Leave a Comment