Search code examples
reactjscomponentsstate

React State not getting updated properly in SetInterval Methods


I've a button in the UI and in OnClick event handler, I've to run a set Interval timer.In Set Interval timer I'm checking for a condition and if the condition is met I'm updating the state,But It is not working properly.

import React, { useState, useEffect, useRef } from "react";
import ReactDOM from "react-dom";

function Counter() {
  let [count, setCount] = useState(0);
  let [gg, setgg] = useState(false);

  function countdownTimer() {
    console.log(count + gg.toString());
    if (count > 10) {
      setgg(true);
    }
    setCount((count) => count + 1);
  }

  function handleClick() {
    let id = setInterval(countdownTimer, 1000);
  }

  return (
    <div>
      <button onClick={handleClick}>Click</button>
      <h1>{count + gg.toString()}</h1>
    </div>
  );
}

const rootElement = document.getElementById("root");

// Second interval to demonstrate the issue.
// Fast updates from it cause the Counter's
// interval to constantly reset and never fire.
setInterval(() => {
  ReactDOM.render(<Counter />, rootElement);
}, 1

00);

In the countdownTimer function there is a console.log which is always printing "0 false" but the componenet in UI is updating to the correct number.

Could you please let me know why

  1. the count is always '0' in the console.log
  2. if count is always zero how does the state get updated corretct eveytime?
  3. how can I print the correct value of count in the console.log() in the countdowntimer function.

code sand box link: https://codesandbox.io/s/dank-grass-7o4ms?file=/src/index.js

screenshot of Component updating correctly but the console.log is always zero.

enter image description here


Solution

  • Issue

    1. the count is always '0' in the console.log

    Stale count state enclosed in updfun callback.

    1. if count is always zero how does the state get updated corretct eveytime?

    You used a functional state update so each update correctly updates from the previous state, not the state from when the callback was enqueued.

    1. how can I print the correct value of count in the console.log() in the countdowntimer function.

    Use an useEffect to issue a side-effect of logging state when it updates, and to also check the count greater than 10 to set gg state.

    Edit react-state-not-getting-updated-properly-in-setinterval-methods

    function Counter() {
      const [count, setCount] = useState(0);
      const [count, setCount] = useState(0);
      const [gg, setgg] = useState(false);
    
      useEffect(() => {
        console.log(count + gg.toString());
        if (count > 10) {
          setgg(true);
        }
      }, [count, gg]);
    
      useEffect(() => () => clearInterval(timerRef.current), []);
    
      function updfun() {
        setCount((count) => count + 1);
      }
    
      function handleClick() {
        timerRef.current = setInterval(updfun, 1000);
      }
    
      return (
        <div>
          <button onClick={handleClick}>Click</button>
          <h1>{count + gg.toString()}</h1>
        </div>
      );
    }