zzsolt
zzsolt

Reputation: 41

Using new state in a function after setting it

Can I use the updated state in the same function where it was updated? With the example below, I get 0.

With useEffect I can access the new state right after setting the state, but how can I access it in the function?

As a side question, can I (or should I) use the state for situations when it is not directly connected to what is in the return? Should I use props instead?

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

  const handleClick = async () => {
    setCount(count => (count + 1));
    await new Promise(r => setTimeout(r, 2000));
    console.log(count); // I get 0
  }

  return (
    <div>
      <Button onClick={handleClick}></Button>
    </div>
  )
}

Upvotes: 0

Views: 74

Answers (2)

Viktor W
Viktor W

Reputation: 1149

No you cannot (or perhaps you can with a little bit of trickery as I'll show you). With functional components, state is a little bit different. Your handleClick function gets created when the component renders, and because of how JavaScript works, it gets attached to the "scope" of that particular render. Even after the timeout, it is still in that old scope.

One way to solve this could be to use a ref.

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

    const countRef = useRef(count)
    countRef.current = count

    const handleClick = async () => {
        setCount(count => (count + 1)); 
        await new Promise(r => setTimeout(r, 2000)); 
        console.log(countRef.current); 
    } 

    return ( 
        <div>
            <Button onClick={handleClick}></Button>
        </div>
    )
}

This will update the ref when the component is re-rendered. This update will change all refs, even the ones in the old scopes.

However, I use React quite a lot and I am certain that I have never been required to use this in practice. I'd say it's bad practice: even with a timeout, you cannot be 100% certain that the state has actually have had enough time to update, so this could lead to weird bugs. Why would you actually want to do this? Can't you instead put your code that requires the new state in an useEffect for example?

As for the side-question: You should use state when you need to re-render the component whenever the state changes. If you do not want your component to re-render when the state changes, you should use another method of storing the data (for example refs).

Upvotes: 1

Lhew
Lhew

Reputation: 624

You just can’t. That a reason why I use useReducer.

Upvotes: 1

Related Questions