1

I'm trying to periodically run a calculation (every 5 seconds) and update a component's state with the calculated value using a setInterval timer. What I've seen is that the updateCalculation() function does get called every 5 seconds but when monitoring the memory usage using the Chrome devtools it just keeps on growing endlessly on every call by setInterval. The memory never seems to get released.

Snapshot 1:
snapshot 1 Snapshot 2:
snapshot 2

What could be a possible workaround for running calculations periodically? I'm still pretty new to React and am really not sure what I'm doing wrong.

class MyComponent extends React.PureComponent {
    constructor(props) {
        super(props);
        this.state = {
            calculated: []
        };
    }

    componentDidMount() {
        this.calculationUpdater = setInterval(() => this.updateCalculation(), 5000);
    }

    componentWillUnmount() {
        clearInterval(this.calculationUpdater);
    }

    // Memory leak here
    // The function that gets called by setInterval to calculate data and update the state
    updateCalculation() {
        let data = [];

        for (let i = 0; i < 60000; i++) {
            data.push({x: i, y: i, z: i});
        }

        this.setState({
            calculated: data
        });
    }

    render() {
        return (
            <React.Fragment>
                <Child calc={this.state.calculated} />
            </React.Fragment>
        );
    }
}

I'm not doing anything special with the Child component at the moment. This is what it looks like:

class Child extends React.PureComponent {

    render() {
        return (
            <div></div>
        );
    }
}
Rocky
  • 38
  • 4
  • If you're using `setInterval` alongside React, you're probably doing it wrong, and _you're_ definitely doing it wrong. Look into how React manages DOM updates via state (it's actually pretty simple and the official React docs are great). – The Onin Jul 09 '20 at 02:36
  • 1
    @NinoŠkopac I actually based this off of the "Clock" tutorial here: https://reactjs.org/docs/state-and-lifecycle.html#adding-lifecycle-methods-to-a-class – Rocky Jul 09 '20 at 03:03
  • What's happening in the child? I don't think the answer is in the above, since on its own this isn't reproducible. – Pavlos Karalis Jul 09 '20 at 03:57
  • @PavlosKaralis I'm currently not doing anything special in the Child component. Please see my updated question. – Rocky Jul 09 '20 at 14:45

2 Answers2

1

EDIT: Check following post: Does JavaScript setInterval() method cause memory leak?

You are not clearing the interval because you are are not setting or reading state correctly. So if your component keep getting mounted and unmounted, you set a new interval but do not clear the interval on unmount.

this.calculationUpdater = setInterval(() => this.updateCalculation(), 5000);

This should be

const calculationUpdater = setInterval(() => this.updateCalculation(), 5000);
console.log(calculationUpdater )
this.setState({calculationUpdater : calculationUpdater})

And you access the state as following:

console.log(this.state.calculationUpdater);
clearInterval(this.state.calculationUpdater);
Çağatay Sel
  • 801
  • 7
  • 14
  • I tried your example by storing and clearing the interval in the state but unfortunately I'm still having the same issue. – Rocky Jul 09 '20 at 15:21
  • I have edited my answer with debug statements. Could you check your console and confirm the output of console.logs are identical. You should also be able to see how many times setInterval() method gets called in your console. Does it keep getting called? – Çağatay Sel Jul 09 '20 at 15:30
  • Yes, the `setInterval()` method does get called every 5 seconds. `componentWillUnmount()` does not get executed. I believe the problem is with me only clearing the interval in `componentWillUnmount()`. The thing is that this application is going to be running for **days** and the component will not actually be unmounted, hence the memory of `setInterval()` not being cleared. – Rocky Jul 09 '20 at 15:45
  • There's only one instance of setInterval running though since its called in componentDidMount, not componentWillUpdate. It's set up exactly as the example on React docs. – Pavlos Karalis Jul 09 '20 at 15:55
  • Check the post in my answer which explains the situation you observe here. – Çağatay Sel Jul 09 '20 at 16:25
0

The only thing I can suggest is to try switching from PureComponents to Components; I noticed my initial snapshot was laggier for PureComponents, though either way my results were not like yours.

Pavlos Karalis
  • 2,893
  • 1
  • 6
  • 14