0

I am new to React and have a hard time understanding why when I call useEffect after I just set the new state on a variable, the new value is undefined. Can someone also explain why the second UseEffect hook is called twice. Is it because it's called on initial mount, and then called when it finally changes state from the first useEffect? How can I get it to fire only once val has a defined value that was set in the first useEffect?

import React from 'react';
import {useState, useEffect} from 'react'

export function App(props) {
  const [val, setVal] = useState();
  useEffect(() => {
    setVal("hello");
  },[]);
  useEffect(() => {
    console.log("value: ", val);
  }, [val])

  return (
    <div className='App'>
    </div>
  );
}
anon
  • 43
  • 4
  • Calling `useEffect` doesn't set the value--calling `useEffect` registers a funtion that does something at an arbitrary time in the future based on its dependencies. – Dave Newton May 10 '23 at 20:30
  • I understand that, but Im using setState in the useEffect though which sets the value, on intiail load right? – anon May 10 '23 at 20:34
  • 1
    @anon: *"which sets the value, on intiail load right?"* - No. It queues a state update to occur after the component finishes rendering. That state update then triggers a re-render. If you want the state to have a value when the component first loads, initialize the state to that value: `const [val, setVal] = useState("hello");` – David May 10 '23 at 20:36

1 Answers1

1

The code is working exactly as I'd expect it to.

On (or more specifically, immediately after) the first render, both effects execute. Which:

  • queues a state update and
  • logs undefined to the console

Then when state is updated, the component re-renders. This re-render has a new state value for val, which triggers the second useEffect to execute. Which:

  • logs "hello" to the console

How can I get it to fire only once val has a defined value that was set in the first useEffect?

If you want something to happen conditionally, you'd use an if statement. For example:

useEffect(() => {
  if (val) {
    console.log("value: ", val);
  }
}, [val])

This will only log val to the console if it has a "truthy" value.

David
  • 208,112
  • 36
  • 198
  • 279
  • This makes a lot of sense. One question though, how is it that in this case, refreshToken is set on the first UseEffect, and used on the second UseEffect without checking for a valid value without a problem? https://github.com/WebDevSimplified/spotify-clone/blob/main/client/src/useAuth.js – anon May 10 '23 at 20:41
  • 1
    @anon: *"without checking for a valid value"* - Look at the first line of the second `useEffect` again. The code is using an `if` statement to conditionally perform an action. – David May 10 '23 at 20:44
  • Oops thought the whole body was executing only if that if condition was true, didnt see the return at the end of line. Got it, thanks! – anon May 10 '23 at 20:45