1

I have a doubt regarding, how hooks like useCallback() work when the variables, arrow functions, and states used in it and its dependency, are declared before and after the useCallback().

Note: The code is processed through Babel, which transforms it to ES5. This means all const and let declarations are converted to var.

Scenario 1

function App() {
  const [counter, setCounter] = useState(0);

  const increment = useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  const decrement = useCallback(() => {
    setCounter(counter - 1);
  }, [counter]);

  //question snippet below 

  const incrementOtherCounter = useCallback(() => {
    console.log("runner value :", runner());
    console.log("this is otherCounter:", otherCounter);
    setOtherCounter(otherCounter + 1);
  }, [otherCounter, runner]);

  const [otherCounter, setOtherCounter] = useState(0);

  const runner = () => {
    return "Something ran! :" + counter;
  };

   //question snippet above 


  return (
    <div className="App">
      <button onClick={decrement}>Decrement</button>
      {` ${counter} `}
      <button onClick={increment}>Increment</button>
      <button onClick={incrementOtherCounter}>incrementOtherCounter</button>
    </div>
  );
}

In this scenario, whenever I run the incrementOtherCounter() function the result is as follows

runner value :Something ran! :0

this is otherCounter: 0

And no matter if update/increment the counter state or rerun the incrementOtherCounter() the result stays the same (counter and otherCounter remain 0).

Scenario 2

function App() {
  const [counter, setCounter] = useState(0);

  const increment = useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  const decrement = useCallback(() => {
    setCounter(counter - 1);
  }, [counter]);

  //question snippet below 
  
  const [otherCounter, setOtherCounter] = useState(0);

  const incrementOtherCounter = useCallback(() => {
    console.log("runner value :", runner());
    console.log("this is otherCounter:", otherCounter);
    setOtherCounter(otherCounter + 1);
  }, [otherCounter, runner]);

  const runner = () => {
    return "Something ran! :" + counter;
  };

   //question snippet above 

  return (
    <div className="App">
      <button onClick={decrement}>Decrement</button>
      {` ${counter} `}
      <button onClick={increment}>Increment</button>
      <button onClick={incrementOtherCounter}>incrementOtherCounter</button>
    </div>
  );
}

In this scenario, running the incrementOtherCounter() produces the correct output (as if runner() and otherCounter state is defined before incrementOtherCounter()), but the counter state in runner() arrow function, seems to lag behind the actual state updates. For instance, if I increment the counter, the runner() function returns the state with a delay of one update cycle.

Result of scenario 2: scenario 2

Scenario 3

function App() {
  const [counter, setCounter] = useState(0);

  const increment = useCallback(() => {
    setCounter(counter + 1);
  }, [counter]);

  const decrement = useCallback(() => {
    setCounter(counter - 1);
  }, [counter]);

  //question snippet below       

  const runner = () => {
    return "Something ran! :" + counter;
  };

  const incrementOtherCounter = useCallback(() => {
    console.log("runner value :", runner());
    console.log("this is otherCounter:", otherCounter);
    setOtherCounter(otherCounter + 1);
  }, [otherCounter, runner]);

  const [otherCounter, setOtherCounter] = useState(0);

   //question snippet above 

  return (
    <div className="App">
      <button onClick={decrement}>Decrement</button>
      {` ${counter} `}
      <button onClick={increment}>Increment</button>
      <button onClick={incrementOtherCounter}>incrementOtherCounter</button>
    </div>
  );
}

In this scenario,everything seems fine as if i have declared the runner() and otherCounter on top of the incrementOtherCounter().

Result of scenario 3: enter image description here

I am not able to understand how things are working in scenarios 2 and 3 i.e how is incrementOtherCounter() producing correct values of counter and otherCounter in scenario 3 and lags behind one cycle in scenario 2?

14
  • 2
    I don’t need to. That is not a Stack Overflow policy. Make your question self contained. Some other thing could be of concern in the sandbox which is not a part of the question. Also URLs die. Commented Jul 16, 2024 at 7:55
  • 1
    Seeing the full code now, all scenarios should throw a ReferenceError. If it doesn’t, your implementation is not doing the right thing. What JavaScript engine are you using? If NodeJS, what version of NodeJS? Commented Jul 16, 2024 at 9:26
  • 1
    @jdsingh You need to fix the const problem. Until you get the correct variable values, it is moot to discuss how react works. Commented Jul 17, 2024 at 8:41
  • 1
    @jdsingh It doesn't work with ES5 either. It just doesn't throw an exception in your face, but the code is still broken if you use the variable before you assign a value to it. Simply fix the code instead of trying to understand how the broken code behaves. Commented Jul 17, 2024 at 16:18
  • 1
    "How do hooks like useCallback() work when the variables, arrow functions, and states used in it and its dependency, are declared after the useCallback()" - they work in the same way as if you simply haven't passed the dependency, or written undefined in the dependency array. The dependency is therefore broken. Commented Jul 17, 2024 at 16:22

0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.