Gregory Kafanov
Gregory Kafanov

Reputation: 357

How to get newly changed value after apply React useState in a handler?

Here is a React code chunk:

const [win, setWin] => useState(false)
const [guessedNumber, setGuessedNumber] => useState(undefined)

const clickHandler = () => {
   setGuessedNumber(randomNumber())

   if(guessedNumber === 10) {
     setWin(true)
   }
}

Explanation: after clicking on button (not presented here) the handler clickHandler fires. Generates random number, setGuessedNumber hook runs. But due to batching the new value of guessedNumber we can find after clickHandler do it works. But I need to see the new value of guessedNumber immediately.

Here is my solution I have done:

const [win, setWin] => useState(false)
const [guessedNumber, setGuessedNumber] => useState(undefined)

const clickHandler = () => {
   const rndNum = randomNumber()

   setGuessedNumber(rndNum)

   if(rndNum === 10) {
     setWin(true)
   }
}

The setGuessedNumber I use for rerender, rndNum for the calculations and logics.

Is it right solution? Or there is something React'ish?

Upvotes: 0

Views: 986

Answers (3)

user16435030
user16435030

Reputation:

I'm not sure why you're storing state for win when you already know that you're winning at "10", seems like that logic should be somewhere else which is why you're racking your brain with these workarounds.

const [number, setNumber] = useState()

...

return <>
  ...
  {number === 10 && <div>You're winning!</div>}
</>

Upvotes: 2

Ernesto Stifano
Ernesto Stifano

Reputation: 3130

Your code is perfectly valid and correct. React will queue state change requests and apply them at the right time after calculating the minimum DOM modification.

Actually, in your case it seems to be the best solution. The only alternative that comes to my mind is to use useEffect hook as follows:

const [win, setWin] = useState(false);
const [guessedNumber, setGuessedNumber] = useState(undefined);

const clickHandler = useCallback(() => {
    setGuessedNumber(randomNumber());
}, [randomNumber]);

useEffect(() => {
    if (guessedNumber === 10) {
        setWin(true);
    }
}, [guessedNumber]);

The useEffect callback will execute each time guessedNumber changes and the component re-renders.

As I mentioned before, in your case I think that your solution will be more efficient as only one re-render will be triggered!

Upvotes: 1

Akash
Akash

Reputation: 103

What you have done in the second example is correct.

const [win, setWin] => useState(false)
const [guessedNumber, setGuessedNumber] => useState(undefined)

const clickHandler = () => {
   const rndNum = randomNumber()

   setGuessedNumber(rndNum)

   if(rndNum === 10) {
     setWin(true)
   }
}

These hooks are asynchronous. They just queue the updates rather than immediately executing them. You can refer this. https://linguinecode.com/post/why-react-setstate-usestate-does-not-update-immediately

Upvotes: 1

Related Questions