First we can reproduce the problem as you describe it. You should see that the same 'render id' is appearing multiple times, and that new 'render ids' are being added to the stack each iteration. This is because you're creating a new interval every time the component renders, and every interval triggers a new render.
const randomID = () => Math.random().toString(36).substring(7);
class App extends React.Component {
constructor(props){
super(props);
this.state={
x: 0,
}
};
render() {
const thisRenderId = randomID();
setInterval(() => {
console.log(`${thisRenderId} | updating state`)
const state = this.state;
this.setState({ x: state.x + 100 });
}, 5000);
return (
<div>
{this.state.x}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
What's happening here is:
- Call the constructor, state =
{ x: 0 }
- Call the render function, add the function within the
setInterval call to the call stack, to be executed after 1000 milliseconds
- Render the component
- [wait 1000 milliseconds]
- Execute the function settings state to
{ x: 400 }
- State is now updated - so we need to rerender (GOTO 3)
etc.
We don't want to update state in any way during the render function as it is going to trigger another render.
There are lots of ways around this problem, but you might want to consider componentDidMount():
const randomID = () => Math.random().toString(36).substring(7);
class App extends React.Component {
constructor(props){
super(props);
this.state={
x: 0,
}
};
componentDidMount() {
const mountId = randomID();
setInterval(() => {
console.log(`${mountId} | updating state`);
const state = this.state;
this.setState({ x: state.x + 100 });
}, 1000);
}
render() {
return (
<div>
{this.state.x}
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById('app')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="app"></div>
With this example, you can hopefully see that there are no new versions of the interval being added to the stack - there is one version, and it is setup when the component mounts.
setIntervalwithin your component in this way in your actual code? In the code you show here, you'll set a new interval every time the component rendersavailchanges totrueso now the timer starts asavailTime...