Reputation: 191
SetInterval is working fine, but clearInterval is not working
See my code, i have parent class Channel and and Child class Body, within body when componentDidMount is called, then i setInterval for function refreshState. In refreshState function i try to clearInterval which is not working
var Header = require('../../common/header.jsx');
var Sidebar = require('../../common/sidebar.jsx');
var Footer = require('../../common/footer.jsx');
var Body = React.createClass({
componentDidMount: function() {
this.intervalId = setInterval(this.refreshStats, 1000);
},
componentWillUnmount: function(){
clearInterval(this.intervalId);
},
refreshStats: function() {
console.log(this.intervalId);
clearInterval(this.intervalId);
},
render: function() {
return (
<Container id='body'>
<Grid>
<Row>
<Col sm={12}>
<PanelContainer>
<Panel>
<PanelBody>
Test
</PanelBody>
</Panel>
</PanelContainer>
</Col>
</Row>
</Grid>
</Container>
);
}
});
var Channel = React.createClass({
mixins: [SidebarMixin, State],
render: function() {
var classes = React.addons.classSet({
'container-open': this.state.open
});
return (
<Container id='container' className={classes}>
<Sidebar />
<Header />
<Body />
<Footer />
</Container>
);
}
});
module.exports = Channel;
Upvotes: 17
Views: 39167
Reputation: 451
You can refer to this example: https://beta.reactjs.org/reference/react/useRef#referencing-a-value-with-a-ref
Since you do not want to trigger a re-render for your state change, it is better to use a ref.
In a class component you can use this in your constructor
this.intervalRef = React.createRef();
For a functional component:
const intervalRef = useRef();
Upvotes: 0
Reputation: 3
I think you need to pass interval id. If you log this.intervalId it will object.
So your code should be like: clearInterval(this.intervalId._id);
Upvotes: 0
Reputation: 1823
Sometimes you need to run a command in an interval using window.setInterval.
When you navigate away from the component (to simulate unmounting), the interval still runs.
Even worse, when you navigate back to Greeting component, another interval process starts!
How to Fix the Issue You need to save the interval ID when you call the setInterval
class Example extends Component {
intervalID = 0;
componentDidMount() {
this.intervalID = setInterval(this.hello, 1000);
}
...
}
To cancel setInterval, you need to call clearInterval, which require the interval ID returned when you called setInterval.
The best place to do is right before the component unmounts (componentWillUnmount).
class Example extends Component {
intervalID = 0;
componentDidMount() {
this.intervalID = setInterval(this.hello, 1000);
}
componentWillUnmount() {
clearInterval(this.intervalID);
}
}
Upvotes: 6
Reputation: 937
I got it working by using clearInterval on the internal Id from the object returned.
componentDidMount() {
this.interval = setInterval(this.timer, 1000)
console.log(this.interval) // Timeout {_id: 5, _clearFn: ƒ}
}
componentWillUnmount() {
clearInterval(this.interval._id)
}
Upvotes: 3
Reputation: 27306
Another way is to save it directly on this
:
var Body = React.createClass({
componentDidMount: function() {
this.intervalId = setInterval(this.refreshStats, 1000);
},
componentWillUnmount: function(){
clearInterval(this.intervalId);
},
refreshStats: function() {
console.log(this.intervalId);
clearInterval(this.intervalId);
},
render: function() {
...
}
});
This requires fewer lines of code but it feels a little less clean. I myself save it on state
as the accepted answer suggests, but I am posting this in case someone more knowledgeable might comment on which method is more idiomatic.
Note also that by using the React Timer mixin you don't have to worry about unmount cleanup - this applies to whether you save the intervalId
in state
or on this
.
Upvotes: 20
Reputation: 67336
In order to keep a handle on the intervalId
, you would need to save it in state
:
var Body = React.createClass({
getInitialState = function() {
return {};
},
componentDidMount: function() {
intervalId = setInterval(this.refreshStats, 1000);
this.setState({intervalId: intervalId});
},
componentWillUnmount: function(){
clearInterval(this.state.intervalId);
},
refreshStats: function() {
console.log(this.state.intervalId);
clearInterval(this.state.intervalId);
},
render: function() {
...
}
});
Otherwise, it won't survive the render cycle.
Upvotes: 17