3
const [test, setTest] = useState("");
useEffect(() => {
    setTest("NOT EMPTY");
    if(test) {
        console.log(test)
    } else {
        console.log("ITS EMPTY")
    }

}, [])

this is a simplified form of my code when I save it and the page automatically refreshes because of nodemon output is : NOT EMPTY

but when i refresh the page or hit f5 output is : EMPTY

4 Answers4

1
useEffect(() => {
    setTest("NOT EMPTY");
    if(test) {
        console.log(test)
    } else {
        console.log("ITS EMPTY")
    }

}, [test]) // pass test as a dependency

On component first load you'll see "ITS EMPTY" then once the state updates you'll see "NOT EMPTY"

Further reading: https://overreacted.io/a-complete-guide-to-useeffect/

SakoBu
  • 3,972
  • 1
  • 16
  • 33
1

It's about synchronously invoking functions that are asynchronous and depending on each other. It's a situation that you must always avoid: let your logic to be dependent on the time some async function resolves. And setState (or the setter function of useState hook) is an example of such function.

To be more precise: a setState function (in your case setTest) is an async operation. If React happens to set the test value before executing the first if-statement, your if executes the first clause, and if not (which you can't guess and depend on!), the else-block.

The times of React executing it's functions differ, depending on many things, hence the difference between "normal" refreshing and nodemon.

What I'd suggest in your case is to move this if-else code to it's own useEffect with [test] as a dependency.

k-wasilewski
  • 3,943
  • 4
  • 12
  • 29
1

Thing is that state doesn't always updates right after you set it. Check out this question, there are some solutions for your problem.

1

setState in React is not synchronous.

const [test, setTest] = useState("");

useEffect(() => {
    setTest("NOT EMPTY");
    // setTest() is not done running yet...
    if (test) {
        console.log(test)
    } else {
        console.log("ITS EMPTY")
    }
}, [])

Here's something you can do instead, since you know what test's value will be if you're setting it in-scope.

const [test, setTest] = useState("");

useEffect(() => {
    const newTest = "NOT EMPTY"
    setTest(newTest);

    // do things with `newTest` instead of `test`
}, [])

Here is a more in-depth explanation of how to work around setState being async.

Michael Lee
  • 273
  • 1
  • 6