Minh Tien
Minh Tien

Reputation: 72

Can not get latest state in React hook | Stale Closure Issue

I have a React app, there's a count increase every second, click on the button will alert the latest count after 2 seconds.

I solved this issue by using "Class component" but I want to understand the Stale closure issue of "Function component".

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

  React.useEffect(() => {
    setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
  }, []);

  const showCurrentCount = () => {
    setTimeout(() => {
      alert(count);
    }, 2000);
  };

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => showCurrentCount()}>show</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>

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

Upvotes: 2

Views: 1252

Answers (2)

Minh Tien
Minh Tien

Reputation: 72

I just fixed my issue by using useRef.

React documentation: https://reactjs.org/docs/hooks-reference.html#useref

function App() {
  const refCount = React.useRef();

  const [count, setCount] = React.useState(0);
  refCount.current = count;

  React.useEffect(() => {
    setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
  }, []);

  const showCurrentCount = () => {
    setTimeout(() => {
      alert(refCount.current);
    }, 2000);
  };

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={showCurrentCount}>show</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>

Upvotes: 0

Amila Senadheera
Amila Senadheera

Reputation: 13245

You can fix the stale value issue by using the callback method of setState. Inside the callback, alert the count return the same count.

  const showCurrentCount = () => {
    setTimeout(() => {
      setCount((count) => {
         alert(count);
         return count;
      });
    }, 2000);
  };

Demo

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

  React.useEffect(() => {
    setInterval(() => {
      setCount(c => c + 1);
    }, 1000);
  }, []);

  const showCurrentCount = () => {
    setTimeout(() => {
      setCount((count) => {
         alert(count);
         return count;
      });
    }, 2000);
  };

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={() => showCurrentCount()}>show</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script src="https://unpkg.com/react@17/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js" crossorigin></script>

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

Upvotes: 1

Related Questions