React SetInterval Conflicts: How to Easily Resolve Them

Pieces 🌟 - Nov 30 '22 - - Dev Community

Two people working at computers.

Have you ever noticed React setInterval functions acting strangely? I’ve found that React Hooks can often help to fix setInterval problems.

In this article, I'll demonstrate how to use setInterval with React Hooks. However, it should be noted that the way setInterval works in Vanilla JavaScript is generally different.

Overview of SetInterval

At each specified timing event, the setInterval() React method repeats a block of code.

This is JavaScript's standard setInterval syntax:

setInterval(function, milliseconds);
Enter fullscreen mode Exit fullscreen mode

Its qualities are:

  • Function: The functions store executable code in a local scope.
  • Milliseconds: The milliseconds are a timer that triggers the function to execute a line of code.

We won't go into more detail in this React setInterval introduction. Instead, please refer to these docs.

Understanding the Effects of SetInterval on React Component Rendering

Every time the state of a component changes, React prepares a render. This takes place once a render has been scheduled. React will look for the ideal time to do this. When we call the setState function in React, we are change the state, which results in an update (in React Hooks, we would use useState).

A component may re-render itself for one of four reasons: state changes, parent (or child) re-renderings, context changes, and hook changes. A widespread misconception is that when the component's props change, re-renders likewise take place. On its own, this is untrue.

If React executes a component more than once when using setInterval without a React Hook, the SetInterval will crash. If you use React and don't use the React Hook to build a counter increment mechanism with React setInterval in an initial page load, it will crash the counter. Therefore, we'll construct a counter increment in this tutorial using React Hooks.

Bad Practices When Using SetInterval in React.js

Below is an example of the problem with utilizing setInterval in JavaScript without a React Hook:

Bad Practice

import { useState } from "react";
import { Fragment } from "react";

function App() {
 let [count, setCount] = useState(0);
 setInterval(() => {
  setCount(count + 1);
}, 2000);

return (
 <Fragment>
  <h1>Count: {count}</h1>
 </Fragment>
 );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

We can see that setInterval was not used in a React Hook in the code above, which is not best practice.

The code will be printed when the page loads for the first time, and along the way, the counter will begin to act improperly, which is not the best scenario.

Resolving Conflicts in React.js

Next, we’ll be using setInterval with React Hooks in various ways.

In this section, we’ll be working with code samples and using a counter in React and a React Hook.

Using SetInterval in a Function-Based Component

Immediately after the page loads for the first time, we'll call setInterval.

Here, we'll make use of setInterval by automating its execution upon a page's initial load:

import { useEffect } from "react";
import { useState } from "react";
import { Fragment } from "react";

function App() {
 let [count, setCount] = useState({
  num: 0,
});

useEffect(() => {
 setInterval(() => {
 setCount((prevState) => {
  return {
   num: prevState.num + 1,
  };
 });
}, 1000);
}, []);

return (
 <Fragment>
  <div style={{ textAlign: "center" }}>
   <h1>Count: {count.num}</h1>
  </div>
 </Fragment>
);
}

export default App;
Enter fullscreen mode Exit fullscreen mode

React Hooks like useState and useEffect were utilized in the code above.

The useState is dependent on its prior state:

setCount((prevState) => {
  return {
   num: prevState.num + 1,
  };
});
 useEffect(() => {
  setInterval(() => {
   setCount((prevState) => {
    return {
     num: prevState.num + 1,
   };
  });
 }, 1000);
}, []);
Enter fullscreen mode Exit fullscreen mode

Output:

A count output.

As you can see, the useEffect method, which has a return function, is used in the code above.

The cleaning function (after the user exits the page and the component unmounts) is the return function.

When the app component loads for the first time, the useEffect hook wraps the setState counter to execute once. This stops React from entering an endless loop.

Kindly note that you can run the code without the cleanup return function. However, it's best practice to use it.

Using setInterval in a React Class-based Component

Next, we’ll look at JavaScript setInterval in a class-based component in code below.

Furthermore, to start setInterval and stop crashes and errors, the setInterval is inserted inside the ComponentDidMount component.

Read more about the React Lifecycle.

Keep in mind that the interval begins as soon as a component loads for the first time. UseEffect is utilized in the function base component.

import React from "react";

class App extends React.Component {
 state = { count: 0 };
 componentDidMount() {
  setInterval(() => {
   this.setState((prevState) => {
    return {
     ...prevState,
    count: prevState.count + 1,
   };
  });
 }, 1000);
}

render() {
 return (
  <div>
   <h1>{this.state.count} Seconds</h1>
  </div>
 );
}
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Output:

The output of the above code, which is 2 seconds.

Calling React SetInterval from onClick in a Function-based Component

We can quickly use an onClick to call setInterval.

import { useState } from "react";

function App() {
 const [count, setCount] = useState(0);

const startCountHandler = () => {
 setInterval(() => {
  setCount((count) => count + 1);
 }, 1000);
};

return (
 <div style={{ textAlign: "center" }}>
  <h1>{count}</h1>
  <br />
  <button onClick={startCountHandler}>Start</button>
 </div>
);
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Output:

The output of a React setInterval function; 551.

Using Clear Interval from an onClick in a Function-based Component

To stop the counter in this area, we'll use clearinterval. It is incredibly simple to use.

import { useState } from "react";

function App() {
 const [count, setCount] = useState(0);
 const [intervalId, setIntervalId] = useState(0);

const startCountHandler = () => {
 let newIntervalId = setInterval(() => {
  setCount((count) => count + 1);
}, 1000);

 setIntervalId(newIntervalId);
};

// Stopping the interval
const stopCountHandler = () => {
 clearInterval(intervalId);
};

return (
 <div style={{ textAlign: "center" }}>
  <h1>{count}</h1>
  <br />
  <button onClick={startCountHandler}>Start</button>
  <br />
  <button onClick={stopCountHandler}>Stop</button>
 </div>
);
}

export default App;
Enter fullscreen mode Exit fullscreen mode

To store the interval id obtained from setInterval, a new state was made. The function for establishing the interval is activated when we click the start button, and we added setIntervalId(newIntervalId) inside the React SetInterval function to save the interval id in the state we generated for the intervalID.

Output:

A React setInterval component's output: 14.

We can start the counter by pressing the start button, and stop the counter by pressing the stop button. By hitting the start button once more, a paused counter can be started again.

Starting SetInterval in a Class-based Component from onClick

In this part, we'll call setInterval from a class-based component's onClick event.

Note: Take care to bind the ‘this’ keyword, or else you can’t access the this.setState in the startCountHandler function.

import React from "react";

class App extends React.Component {
 constructor(props) {
  super(props);
  this.state = { count: 0, intervalId: 0 };

 // Binfing this keyword
 this.startCountHandler = this.startCountHandler.bind(this);
}
startCountHandler() {
 setInterval(() => {
  this.setState((prevState) => {
   return {
    ...prevState,
    count: prevState.count + 1,
   };
  });
 }, 1000);
}

render() {
 return (
  <div>
   <h1>{this.state.count} Seconds</h1>
   <button onClick={this.startCountHandler}>Start</button>
  </div>
 );
}
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Output:

A timer created with a setInterval component.

Stopping the Countdown in Class-based Components Using clearInterval

In this section, we'll utilize clearInterval in a class-based component to stop the counter from running during an onClick event.

Let's get going.

The function that will stop or pause the counter increment will be the React setInterval handler, to which we will bind the keyword "this." Learn more about the “this” keyword.

The code for a class-based component is shown below.

import React, { useEffect, useState } from "react";

class App extends React.Component {
 constructor(props) {
  super(props);
  this.state = { count: 0, intervalId: 0 };

// Binding this keyword
this.startCountHandler = this.startCountHandler.bind(this);
this.stopCountHandler = this.stopCountHandler.bind(this);
}
startCountHandler() {
 let newIntervalId = setInterval(() => {
  this.setState((prevState) => {
   return {
    ...prevState,
    count: prevState.count + 1,
   };
});
}, 1000);

// Append the interval Id to state interval
this.setState((prevState) => {
 return {
  ...prevState,
  intervalId: newIntervalId,
 };
});
}

// Stopping the setInterval with clearinterval
stopCountHandler() {
 if (this.state.intervalId) {
  clearInterval(this.state.intervalId);
 }
}

render() {
 return (
  <div style={{ textAlign: "center" }}>
   <h1>{this.state.count} Seconds</h1>
   <button onClick={this.startCountHandler}>Start</button>
   <br />
   <button onClick={this.stopCountHandler}>Stop</button>
  </div>
 );
}
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Output:

A timer with a start and a stop button.

Utilizing a Backward Counter

import { useState, useEffect } from 'react';

const ForwardCounter = () => {
 const [counter, setCounter] = useState(0);

useEffect(() => {
 const interval = setInterval(() => {
  setCounter((prevCounter) => prevCounter - 1);
 }, 1000);

 return () => clearInterval(interval);
}, []);

 return <h1>{counter}</h1>;
};

export default ForwardCounter;
Enter fullscreen mode Exit fullscreen mode

The aforementioned code is a straightforward example of utilizing setInterval in a React Hook to interact with a backward counter.

Please be aware that using setInterval in a React Hook useEffect will cause the cleanup function to run.

The Cleanup Function in useEffect

In this section, we'll demonstrate how to send a request to a fake server utilizing the useEffect cleanup function rather than while the user is still typing.

The cleaning function, which runs after the user exits the page and the component unmounts, is the return function.

This greatly helps to avoid sending many requests while a user is typing, which would slow down our web app. Creating a search mechanism that returns a list of values from a server in this way is great practice.

Here, we'll implement this process using setTimeout rather than setInterval.

Now, we’ll use clearInterval to do the cleanup operation.

import { useEffect, useState } from "react";

function App() {
 const [enteredValue, setEnteredValue] = useState("");
useEffect(() => {
 const interval = setTimeout(() => {
  if (enteredValue.length > 0) {
  // Make a fetch request in a real project
  console.log("Send a request to a server...");
 }
}, 1000);

 return () => clearInterval(interval);
}, [enteredValue]);

const onChangedHandler = (e) => {
 setEnteredValue(e.target.value);
};

return (
 <div style={{ textAlign: "center" }}>
  <input
   type={"text"}
   onChange={onChangedHandler}
   value={enteredValue}
   style={{ padding: "10px", margin: "40px" }}
  />
 </div>
);
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Output:

A photo of a console log.

We can see from the output in the console that the console log was produced four times, which indicates that I actually waited four times before inputting another character.

Make sure to test this out for yourself to see how it performs.

All I ask is that you start using this in your React project so that you discover its value.

Conclusion

I hope you had a good time reading this article! We learned how to utilize React setInterval and clearInterval in class & function-based components without crashes and errors, as well as how React renders a component and affects setInterval. Start making changes to your app so that it takes advantage of the strategies we discussed in this post. Setting up setInterval in your program allows you to add more features and ensures that everything runs smoothly.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .