React State not getting updated properly in SetInterval Methods

Viewed 327

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

2 Answers

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>
  );
}

You need to first set count value and then update it to state so your countdounTimer should be like

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

OR

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

Click Here For demo

Related