why useEffect is called twice when using useCallbackRef from use-callback-ref

Viewed 599

useCallbackRef is a hook provided by use-callback-ref package

Why does useEffect triggered twice when having in the dependency array the .current of the useCallbackRef result?

import { useCallback, useEffect, useRef, useState } from "react";
import { useCallbackRef } from "use-callback-ref";

function App() {
  const [useCbRefCounter, setUseCbRefCounter] = useState(0);
  const [useCbRefEffectCounter, setUseCbRefEffectCounter] = useState(0);


  const divCbRef = useCallbackRef(null, () =>
    // This is called once
    setUseCbRefCounter((counter) => counter + 1)
  );

  useEffect(() => {
    if(!divCbRef.current) {
      return;
    }

    // This is called twice
    setUseCbRefEffectCounter((counter) => counter + 1);
  }, [divCbRef.current]);
  
  // ...
}

(The useEffect is not triggered with null as one might think)

Sandbox Demo with a comparison of the number of calls when the ref is changing

1 Answers

Most likely this is due to the implementation of useCallbackRef.
divCbRef.current is a mutable object and therefore inside useEffect it is the same for both calls.

But the call to useEffect happens twice due to the fact that the first time the divCbRef.current is null, and the second time it is HTMLDivElement.

If you slightly change the code of the useEffect, then you will see why the effect is called:

  const currentREF = divCbRef.current;
  useEffect(() => {
    if (!divCbRef.current) {
      return;
    }

    console.log(currentREF);

    // This is called twice
    setUseCbRefEffectCounter((counter) => counter + 1);
  }, [currentREF]);

Console output will be

null
<div> </div>
Related