3

Does the order of useCallback function declaration matters? For example:

Functions declared in this order:

  1. const aboveFunction = useCallback(()=>{ logCount() },[logCount])

  2. const logCount = useCallback(()=>{ console.log(count) },[count])

  3. const belowFunction = useCallback(()=>{ logCount() },[logCount])

Notice both aboveFunction and belowFunction refers to the same logCount. After we call setCount(2) ,

aboveFunction() -> logCount() -> count // 0, wheres

belowFunction() -> logCount() -> count // 2

https://codesandbox.io/s/react-hooks-counter-demo-forked-7mofy?file=/src/index.js

/**
  Click increment button until count is 2, then click 
  Above and Below button and check console log
 * Even though the count value is > 0, aboveIncrement console.log(count) still gives 0
 */

import React, { useState, useCallback } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

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

  /** Assuming all the functions below do some intensive stuffs to justify useCallback */
  const aboveFunction = useCallback(() => {
    // ...do other intensive stuff
    logCount("Above count:"); // Above count: 0
  }, [logCount]);

  const logCount = useCallback(
    (str) => {
      // ...do other intensive stuff
      console.log(str, count);
    },
    [count]
  );

  const belowFunction = useCallback(() => {
    // ...do other intensive stuff
    logCount("Below count:"); // Above count: 2
  }, [logCount]);

  return (
    <div className="App">
      <h1>
        Click increment button until count is 2, then click Above/ Below button
        and see console log
      </h1>
      <h2>You clicked {count} times!</h2>
      <div
        style={{
          display: "flex",
          alignItems: "center",
          flexDirection: "column"
        }}
      >
        <button style={{ margin: 10 }} onClick={aboveFunction}>
          Above Increment Function
        </button>
        <button style={{ margin: 10 }} onClick={() => setCount(count + 1)}>
          Increment
        </button>
        <button style={{ margin: 10 }} onClick={belowFunction}>
          Below Increment Function
        </button>
      </div>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

It is apparent that the order of useCallback declaration is important in order for the code to work. However, if we write it this way https://codesandbox.io/s/react-hooks-counter-demo-forked-7mofy?file=/src/index1.js

  let logCount;
  const aboveFunction = useCallback(() => {
    logCount("Above count:"); // Above count: 0
  }, [logCount]);

  logCount = useCallback((str) => {
      console.log(str, count);
    }, [count]
  );

  const belowFunction = useCallback(() => {
    logCount("Below count:"); // Above count: 2
  }, [logCount]);

aboveFunction still gives stale count value. Is there any rule-of-hooks that I'm missing?

Yes a fix here is to apply eslint no-use-before-define. But I wanna understand the reason why .. isn’t functions get hoisted up in JavaScript and the order in which it is declared doesn’t matter?

TylerC
  • 95
  • 1
  • 6
  • *"Assuming all the functions below do some intensive stuffs to justify useCallback"* useCallback does not change anything about "intensive stuff". I'd say, just get rid of `useCallback()`s in that code, but I don't understand what exactly you're trying to achieve/why you put them in there in the first place – Thomas Aug 03 '21 at 13:58

1 Answers1

2

Is there any rule-of-hooks that I'm missing?

You are not missing rule-of-hooks but, you are missing no-use-before-define rule.

You have to use the logCount function above the aboveFunction.

In this attached image as well

image

you can see, it's showing a warning for function declaration.

Maybe you can add es-lint in your project and make sure you add this plugin & no-use-before-define as well so that it will show you these types of warning in vs code.

Hope this helps!

Shubham J.
  • 601
  • 5
  • 13
  • But 'no-use-before-def' isn’t fool proof, as u can see the 2nd part of my question. – TylerC Aug 03 '21 at 14:22
  • 2
    And isn’t functions get hoisted up in JavaScript, and the order in which they’re declared doesn’t matter? Or it does matter only when it is wrapped in useCallback? – TylerC Aug 03 '21 at 14:38
  • 1
    These types of `hoisting` we should avoid. It won't help you. It won't give you any advantage, it is only there to increase your pain. You can check this here, https://stackoverflow.com/a/29718445/7348073, as well. But anyways it's a good question you asked. – Shubham J. Aug 04 '21 at 03:49