React Timer App: The setInterval function is being reset after each render operation

I'm currently working on a straightforward timer application that will begin counting seconds when a button is clicked. To implement this, I am utilizing react hooks.

import React, { useState } from 'react'

function Timer() {

  const [seconds, setSeconds] = useState(0);

  const startTimer = () => {
    let timerID = setInterval(setSeconds((prevState) => prevState + 1), 1000);
  };

  return (
    <>
      <p> Seconds {seconds}</p>

      <button onClick={startTimer}> Start Timer </button>
    </>
  );
}


export default Timer;

The setInterval function is being cleared after each rendering phase. Ideally, it should continue running until explicitly stopped. Additionally, the seconds state only increments once with each click of the start timer button.

Answer №1

When using the setInterval method, it is important to provide a function to call. In this case, instead of providing a function, you are invoking the setSeconds method directly, which increments the seconds by 1 immediately. However, since it's not a function, setInterval cannot call it again. To fix this issue, you can wrap the expression with an arrow function:

() => setSeconds((prevState) => prevState + 1)

Here is an example:

const { useState, Fragment } = React;

function Timer() {

  const [seconds, setSeconds] = useState(0);

  const startTimer = () => {
    let timerID = setInterval(
      () => setSeconds((prevState) => prevState + 1) 
    , 100);
  }

  return (
    <Fragment>
      <p> Seconds {seconds}</p>

      <button onClick={startTimer}> Start Timer </button>
    </Fragment>
  )
}


ReactDOM.render(
  <Timer />,
  root
)
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

Here are some important notes to consider:

  1. It is recommended to save the timerID in a ref so that you can clear it later.
  2. Make sure to clear the interval (and set seconds to 0) whenever the "Start Timer" button is clicked, in order to avoid having multiple running timers simultaneously.
  3. Add an effect using useEffect to clear the interval when the component is unmounted. This will prevent any memory leaks and ensure proper cleanup.

Answer №2

  1. setInterval requires a function as its first parameter.
  2. To prevent a memory leak, it is important to clear the previous interval.

    import ReactDOM from "react-dom";
    import React, { useState, useEffect, useRef } from "react";
    
    function Timer() {
      const [seconds, setSeconds] = useState(0);
      const timerId = useRef(null);
    
      useEffect(() => {
        return () => stopTimer();
      }, []);
    
      const startTimer = () => {
        stopTimer();
        timerId.current = setInterval(
          () => setSeconds(prevState => prevState + 1),
          1000
        );
      };
    
      const stopTimer = () => {
        if (timerId.current != null) {
          clearInterval(timerId.current);
        }
      };
    
      return (
        <>
          <p> Seconds {seconds}</p>
          <button onClick={startTimer}> Start Timer </button>
        </>
      );
    }
    
    const rootElement = document.getElementById("root");
    ReactDOM.render(<Timer />, rootElement);
<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>

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Experience the full functionality of Google Maps API without the need for jQuery or PHP with PanTo

I'm not a developer and I find myself stuck in the panTo() function. All I want is to execute this function with an if-else statement without having to reload the Google Map or using jQuery. <body> <div id="map"></div> <d ...

Generate a graph showcasing the frequency of character occurrences within a specific column of a .csv file

I'm currently working on creating a graph using d3.js What I need to accomplish is reading the some_column column in a .csv file and counting the occurrences of | to plot them accordingly on the y-axis. The line should be plotted based on the number ...

``Trouble with React Dropdown menu option selection"

I am encountering challenges with implementing a dropdown menu list for my react app. The issue at hand is that I have an API where one of the keys (key3) has values separated by commas that I wish to display in my dropdown list. The structure of the API ...

Unable to generate webpage source code

Having some trouble with my Next.js project as I'm using getStaticProps and getStaticPath to build a page, but unfortunately, the HTML is not being generated in the page source. This issue is causing problems with SEO, and I haven't implemented r ...

When the Angular UI Bootstrap typeahead ng-model is cleared, it displays as null

The filter is performing admirably, however, after deleting the entered text, the {{filterlist.name}} displays null. This leads to the tables appearing empty due to the presence of null. Check out the demo here: https://plnkr.co/edit/1QVdctw1hr4ggJOtFHUZ? ...

How to pass a String Array to a String literal in JavaScript

I need to pass an array of string values to a string literal in the following way Code : var arr = ['1','2556','3','4','5']; ... ... var output = ` <scr`+`ipt> window.stringArray = [`+ arr +`] & ...

The functionality of the button is affected when it is placed on the same line as a h1 heading

My goal is to have the page title and profile button aligned on the same line in the header of each page. However, I've encountered an issue where the button doesn't function properly when placed on the same line but works fine when separated ont ...

Vue js for filtering and replacing prohibited words

For this scenario, our objective is to screen the words in our input: <input type="text" class="form-control" placeholder="Write something..." v-model="todoInput""> Below are the restricted words that we aim to substitute in the input "restrict ...

Considering a transition from bootstrap to Material UI in React

I'm currently working on transitioning my react app from using bootstrap to Material-UI. However, I've encountered an issue when trying to change the modal - the form doesn't seem to be functioning properly. Since this is my first time using ...

What is the best way to verify changing input fields in vue.js?

Validation of input fields using vuelidate is essential. The input field in question is dynamic, as the value is populated dynamically with jsonData through the use of v-model. The objective: Upon blur, the goal is to display an error if there is one; ho ...

Tips for converting a date string to a date object and then back to a string in the same format

I seem to be encountering an issue with dates (shocker!), and I could really use some assistance. Allow me to outline the steps I have been taking. Side note: The "datepipe" mentioned here is actually the DatePipe library from Angular. var date = new Dat ...

"We are experiencing issues with the app.get function and it is

Although my backend is successfully serving other files, I have encountered an issue with loading new files that are located in a folder named js within the directory. These specific files are not being loaded, and despite spending an hour trying to troubl ...

Creating an object using a string in node.js

I have a string that I am sending from AngularJS to NodeJS in the following format. "{↵obj:{↵one:string,↵two:integer↵}↵}" //request object from browser console To convert this string into an object and access its properties, I am using the serv ...

Jest identifies an open handle when working with an Express application

For quite some time now, I've been grappling with a particular issue. It all started when I was conducting basic integration tests using a MongoDB database. However, I've minimized the code to its simplest form. The only thing left running is a s ...

Choosing the appropriate data type for form data on the server

Seeking assistance on uploading an audio file to my server using the following method: var fd = new FormData(); fd.append('fname', 'test.wav'); fd.append('data', soundBlob); $.ajax({ type: 'POST', url: &apos ...

Performing an HTTP GET request to an endpoint within a RESTful API

I am looking to integrate a feature in my web application that displays the list of online users on my website. To achieve this, I need to make an HTTP GET request to the URL which returns the user data in JSON format. The returned JSON data contains var ...

Encountering Issues with File Uploads in Express.js with Multer

Currently, I am immersing myself in Node.js through the guidance of a book titled "Web Development with Nodejs and MongoDB." However, I have hit a roadblock when attempting to upload an image using Multer. The code snippet causing me trouble is as follows: ...

What is the best way to make an element disappear 5 seconds after the mouse has stopped hovering

#section1 { display: block; } #section2 { display: none; } #container:hover > #section2 { display: block; } <div id="container"> <div id="section1">Section1</div> <div id="section2">Section2</div> </div> ...

Bracket notation accessor cannot be utilized with React aliases

Can someone help me figure out how to create a tabbed-page using the alias feature? I've noticed that JSX doesn't allow object bracket-accessors. Is there an alternative method I could use, considering that the dot-notation would render the alias ...

Modify KeyboardDatePicker to display the full name of the day and month

Date Selector Hey there, I'm looking to modify the date format from Wed, Apr 7 to Wednesday, April 7. Is there a way to display the full name of the day and month instead of the short abbreviation? ...