Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to clearTimeout an async function when componentWillUnmount in a Reactjs component?

Here is the component:

class ChartComp extends Component{
    constructor(props){
        super(props);
        this.timer = null;
        this.loadData = this.loadData.bind(this);
    }

    componentWillMount(){
        this.loadData();
    }

    componentWillUnmount(){
        if(this.timer){
            clearTimeout(this.timer);
        }
    }

    loadData(){
        //...
        getJSON(url, msg=>{ //get data from server
            if(msg.success){
                //...
                this.timer = setTimeout(()=>{this.loadData()}, 30000); //get data and rerender the component every 30s
            }
        })
    }

    render(){
        //...
    }
}

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. So how can I make clearTimeout work?

like image 564
Cinque Avatar asked Jul 12 '17 16:07

Cinque


2 Answers

Set a flag in your class inside componentWillUnmount.

In your async callback, check whether that flag has been set, and, if so, stop immediately.

like image 188
SLaks Avatar answered Sep 21 '22 13:09

SLaks


You can certainly set a flag as suggested by @SLaks. This is similar to the isMounted pattern. ** note I changed to componentdidmount which is a better pattern I think **

class ChartComp extends Component{
    constructor(props){
        super(props);
        this.timer = null;
        this.loadData = this.loadData.bind(this);
    }

    componentDidMount() {
      this._mounted = true;
      this.loadData();
    }

    componentWillUnmount(){
        this._mounted = false;
        if(this.timer){
            clearTimeout(this.timer);
        }
    }

    loadData(){
        //...
        getJSON(url, msg=>{ //get data from server
            if(msg.success && this._mounted){
                //...
                this.timer = setTimeout(()=>{this.loadData()}, 30000); //get data and rerender the component every 30s
            }
        })
    }

    render(){
        //...
    }
}

You can read up more on why that pattern was deprecated here However, doing that naively ends up requiring flags on both the getJSON as well as the subsequent timeout, because basically you need to chain together cancellable promises (where you want to stop any step along the way)

A different paradigm to consider would be to use an observable chain for this. See this blog for details

like image 31
AnilRedshift Avatar answered Sep 22 '22 13:09

AnilRedshift