Using setInterval in React Component - javascript

I was reading the tutorial on the official react website. In the example about life cycle methods, under the componentDidMount method, a timerID is set to the setInterval function.
My question is even though the timerID was initialized, it was never called throughout the application, how does the application work without explicitly calling timerID anywhere in the application. Here is the code below.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);

this.timerID is a numeric, non-zero value which identifies the timer created by the call to setInterval(); this value can be passed to clearInterval to clear the timer.
So when calling the setInterval in componentDidMount like
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
you want to execute the tick() function every 1 sec after the component has mounted. Now when you navigate to another component and your current component has unmounted, if you do not clear the interval call to tick() function, it will continue to be executed.
Hence in the componentWillUnmount function you timer is cleared which is identified by the numeric value returned by setInterval which is stored in this.timerID
componentWillUnmount() {
clearInterval(this.timerID);
}
so the complete code as provided in the React docs is
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);

It's Simple. As soon as it React executes componentDidMount() life cycle method, the timer starts running.
this.timerID = setInterval(
() => this.tick(),
1000
);
The above timer will run until the component gets unmounted (according to your code). It's not a surprise that your code works that way.

In this react document it's written that
We will tear down the timer in the componentWillUnmount() lifecycle
method
So, this.timerID will be used in componentWillUnmount() lifecycle method to stop timer.

Related

State ReactJS and render method

I'm studying chapter State and lifecycle in reactJS with Clock class and I don't understand why I can re-render my variables "myFirstNumber, mySecondNumber, myWord" which are not states when I use this code in CodePen:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {
date: new Date(),
};
this.mySecondNumber = 0;
}
componentDidMount() {
this.myFirstNumber = 0;
this.myWord = "Start";
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date(),
});
this.myFirstNumber += 1;
this.mySecondNumber += 1;
if (this.myFirstNumber ===5) {
this.myWord = "Finish";
}
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
<h2>myFirstNumber from ComponentDidMount: {this.myFirstNumber}</h2>
<h2>mySecondNumber from constructor: {this.mySecondNumber}</h2>
<h2>myWord: {this.myWord}</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
The render method render all DOM each seconde for my variables which are not states ?
When you call this.setState function, the DOM gets rerendered. Here the DOM is getting updated every second when this.state.date gets changed through this.setState, showing new values. However, if you keep date outside of state, you can see that the DOM no longer rerenders, same result if you want to change "myWord" or "firstNumber" without changing anything in state.
When you run tick() the setState part is what triggers the re-render and that will process everything, state or not.
In componentDidMount() you schedule interval which triggers tick() function every second. Inside this function you update component's state by invoking setState() and passing current time as a new state value. Moreover, you modify some local variables of the class. When arguments passed to setState() are processed by JS engine, what happens asynchronously, not immediately after setState() is called, the component updates its state.
Then the render() function is called by the framework. The render() function returns output which reflects the current values of all variables requested inside render() function. If you didn't call setState() inside tick() method then you wouldn't see any changes even though you modify myFirstNumber and other variables after each second.

React refresh component when variable has changed

I am calling a React component BarChart with two props, a name and a value. As you can see in the below code, the variable value is set to a new random number every second:
let random1;
function setRandom() {
random1 = Math.floor(Math.random() * 10) + 1;
}
setRandom();
setInterval(setRandom, 1000);
return (
<div className="Content">
<BarChart name1={"A"} value1={random1}/>
</div>
)
}
Inside the React component I call it by using this.props.value1. When I do a console.log(this.props.value1) each second inside the React component, I get an error that the variable is undefined after the first print is made. So, it prints to the console 1 time and then it just prints an error for all of the rest attempts.
This is how I print the variable inside the component:
setRandom() {
console.log(this.props.value1)
}
componentDidMount() {
this.setRandom();
setInterval(this.setRandom, 1000);
}
What I really want to do is that whenever a new random value is generated outside the component, the component should see that the variable has changed and refresh the component and use the new prop.
Could you please advise me?
The standard way to do this is to make random1 a piece of state information, and then use this.setState to update it.
The first link above has an example of a ticking clock, which is virtually identical to your example of a random number every second. Here's that example, which you can readily adapt to your task:
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {date: new Date()};
}
componentDidMount() {
this.timerID = setInterval(
() => this.tick(),
1000
);
}
componentWillUnmount() {
clearInterval(this.timerID);
}
tick() {
this.setState({
date: new Date()
});
}
render() {
return (
<div>
<h1>Hello, world!</h1>
<h2>It is {this.state.date.toLocaleTimeString()}.</h2>
</div>
);
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
constructor(props) {
super(props);
//innitialize the random number in the state
this.state = {random: Math.floor(Math.random() * 10) + 1};
}
//generate the random number and keep in on the state
setRandom() {
this.setState({random: Math.floor(Math.random() * 10) + 1})
}
//clear the timer when component unmount
componentWillUnmount() {
clearInterval(this.timer);
}
componentDidMount() {
//start the timer when component mount
this.timer = setInterval(()=>this.setRandom(), 1000);
}
//pass the random value from state as props to the component BarChart
return (
<div className="Content">
<BarChart name1={"A"} value1={this.state.random}/>
</div>
)
}

Auto Update value in react component

I'm trying to build a component with auto-updating value based on cookies:
let cookies = 0;
(function count() {
cookies = document.cookie.split("?");
setTimeout(count, 10);
return cookies;
})();
class CartButton extends React.Component {
state = {quantity: cookies.length}
render() {
return (
<Cart onClick={e=>{show_cart()}}>
<Mfont>{this.state.quantity}</Mfont>
<Icon>shopping_cart</Icon>
</Cart>
);
}
}
'count' function works as expected, component is rendered with the latest value returned. Unfortunately, it does not auto-update when 'cookies' are changed. It returns this error:
Warning: render(...): Replacing React-rendered children with a new root component. If you intended to update the children of this node, you should instead have the existing children update their state and render the new components instead of calling ReactDOM.render.
I have tried various variations here but still can't figure it out :/
componentDidMount will get execute only once when your component loads first time. This is the correct place to write any logic which we need to execute after page load.
Try this,
class CartButton extends React.Component {
//It is good to have a constructor for the component which has state
constructor(props){
super(props);
this.state = {quantity: cookies.length}
this.updateQuantity;
}
componentDidMount(){
this.updateQuantity = setInterval(()=> {
cookies = document.cookie.split("?");
this.setState({quantity: cookies.length})
},10)
}
//Don't forget to clear any setInterval like below
componentWillUnmount(){
clearInterval(this.updateQuantity);
}
render() {
return (
<Cart onClick={e=>{show_cart()}}>
<Mfont>{this.state.quantity}</Mfont>
<Icon>shopping_cart</Icon>
</Cart>);
}
}
Here your CartButton is not updating even though count is working fine because CartButton is not listening to your cookies variable. React component updates only when there is either props or state change.
You can something like this..
class CartButton extends React.Component {
state = {quantity: cookies.length}
componentDidMount(){
setInterval(function count() {
cookies = document.cookie.split("?");
this.setState({quantity: cookies})
}.bind(this), 10)
}
render() {
return (
<Cart onClick={e=>{show_cart()}}>
<Mfont>{this.state.quantity}</Mfont>
<Icon>shopping_cart</Icon>
</Cart>);
}
}

Execute function in stateless component after timeout

I have a loading spinner in a stateless functional component that I'm using while I check for props.
I'd like to use setTimeout to have the loading spinner display for 5 seconds and then change the content if props are still not available, but this code doesn't seem to work:
function LoadingIndicator() {
let content = <span>Loading Spinner Here</span>;
setTimeout(() => {
console.log('6 second delay');
content = <span>Page could not be loaded.</span>;
}, 6000);
return (
<div>
{content}
</div>
);
}
I believe this doesn't work because nothing tells react to re-render this component, but I'd prefer not to upgrade to a container if possible.
Move the timer to the parent. Have the timer change a state value and in its render, pass that state value as a prop to your LoadingIndicator.
Make your component stateful, so you can change its state easily.
class SpinnerComponent extends React.Component {
constructor() {
super();
this.state = { tooLong: false };
}
componentDidMount() {
var thiz = this;
setTimeout(function () {
thiz.setState({ tooLong: true });
}, 1000);
}
render() {
let content = 'Spinner...';
if (this.state.tooLong) {
content = 'It takes too much time...';
}
return (
<div>{content}</div>
);
}
};
ReactDOM.render(
<SpinnerComponent />,
document.getElementById("app")
);
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

React-Native: run a function in background while component is loaded

In a component, while the listview and everything is loaded.
Is it possible to run a function in background to reload the listview data in every few minutes?
If yes,
When user leaves the component ( go to another tab, iOS ), will the function stop?
You can do this by adding a setInterval in componentDidMount and clearing it in componentWillUnmount.
let interval;
class HelloWorld extends Component {
componentDidMount() {
interval = setInterval(() => {
// do what you want here.
}, 10000);
}
componentWillUnmount() {
clearInterval(interval);
}
render() {
return (
<Text>Hello world!</Text>
);
}
}

Categories

Resources