1

So I have an issue that my react going crazy when the count is passing 10, I trying to make a count from 0<??(Unlimited count) after the count passing 10 the numbers start to go crazy instead of 11 I get non-stop switching numbers. This is my code :

<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>

import React, { useState } from 'react';
function CountUp() {
    
    const [i, setI] = useState(0);
    function timeOutExample() {
        setI(i + 1);
    }
    setInterval(timeOutExample, 1000);
    return (
        <span>{i}</span>
    );
}
export default CountUp;

If you see something wrong here please tell me I searching for an answer for 3 hours without any success.

Oded
  • 73
  • 9
  • 1
    For next time, you can make your example of your problem **runnable** using Stack Snippets (the `[<>]` toolbar button). Stack Snippets support React, including JSX; [here's how to do one](http://meta.stackoverflow.com/questions/338537/). – T.J. Crowder Nov 25 '20 at 16:23
  • this was answered in this post by using UseEffect hook https://stackoverflow.com/questions/53395147/use-react-hook-to-implement-a-self-increment-counter – Ron Gabbay Nov 25 '20 at 16:29
  • Does this answer your question? [Use React hook to implement a self-increment counter](https://stackoverflow.com/questions/53395147/use-react-hook-to-implement-a-self-increment-counter) – Ron Gabbay Nov 25 '20 at 16:41

2 Answers2

4

You're starting a new interval timer every time your component is rendered. Eventually you end up with hundreds, possibly even thousands of them, all overlapping each other.

Two ways to solve it:

  1. Just set a one-off timer — which will then cause re-rendering, which will set anothe rone-off timer, etc. Be sure to cancel the timer when the component is unmounted. (Because if the timer callback is called after the component is unmounted, you'll try to set state on an unmounted component, and React will write an error to the console.)

  2. Set one interval timer when the component is first mounted (using useEffect with an empty dependency array), and cancel it when the component is unmounted.

Since you have to cancel the timer when being unmounted either way, an interval timer via useEffect is probably simplest. Be sure to use the callback form of the state setter (because the i you close over will be stale on subsequent calls to the interval callback):

function CountUp() {
    const [i, setI] = useState(0);
    useEffect(() => {
        // This is called once when the component is mounted
        const handle = setInterval(() => {
            setI(i => i + 1);
        }, 1000);
        // Return the unmount cleanup handler:
        return () => {
            // This is called once when the component is unmounted
            clearInterval(handle);
        };
    }, []);
    return (
        <span>{i}</span>
    );
}

Live Example:

const {useState, useEffect} = React;

function CountUp() {
    const [i, setI] = useState(0);
    useEffect(() => {
        // This is called once when the component is mounted
        const handle = setInterval(() => {
            setI(i => i + 1);
        }, 1000);
        // Return the unmount cleanup handler:
        return () => {
            // This is called once when the component is unmounted
            clearInterval(handle);
        };
    }, []);
    return (
        <span>{i}</span>
    );
}

ReactDOM.render(<CountUp/>, document.getElementById("root"));
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.0/umd/react-dom.production.min.js"></script>
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
0

This was answered in this post by using UseEffect hook

Use React hook to implement a self-increment counter

your SetInterval is happening over and over again since you re-render the page every time your state is changing

const [i,setI] = useState(0)

  useEffect(()=>{
      const interval = setInterval(() => {
        setI(i=>i+1)
      }, 1000);;
      return ()=>{
        clearInterval(interval)
      }

  },[])
Ron Gabbay
  • 99
  • 4