Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the exact behaviour of useRef react hook? Does the object get recreated on each rerender?

I'm creating an app where I need to create an object on initial render and keep it for the whole component life.

My code looks somehow like that right now:

function Component() {
  const obj = useRef(new Smth());
  return (
    <div>
      <button onClick={obj.current.p}>p</button>
      <button onClick={obj.current.c}>c</button>
    </div>
  );
};

The React documentation says:

useRef returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

from: https://reactjs.org/docs/hooks-reference.html#useref

and it seems that I use it properly. Yet, Hooks FAQ says:

You might also occasionally want to avoid re-creating the useRef() initial value. For example, maybe you want to ensure some imperative class instance only gets created once:

function Image(props) {
  // ⚠️ IntersectionObserver is created on every render
  const ref = useRef(new IntersectionObserver(onIntersect));
  // ...
}

useRef does not accept a special function overload like useState. Instead, you can write your own function that creates and sets it lazily:


function Image(props) {
  const ref = useRef(null);

  // ✅ IntersectionObserver is created lazily once
  function getObserver() {
    if (ref.current === null) {
      ref.current = new IntersectionObserver(onIntersect);
    }
    return ref.current;
  }

  // When you need it, call getObserver()
  // ...
}

from: https://reactjs.org/docs/hooks-faq.html#is-there-something-like-instance-variables

So does the initial value get recreated or not?

like image 483
Likepineapple Avatar asked Sep 08 '25 08:09

Likepineapple


1 Answers

So does the initial value get recreated or not?

Yes the initial value can be re created but then it is ignored.
For example here:

function Table(props) {
  // ⚠️ someFunc() is called on every render
  // But after first (or maybe second render if it is strict mode) it's value is ignored
  const rows = useRef(someFunc(props.count));
  // ...
}

It is similar with useState, if you pass a value to its constructor it gets recomputed but then it gets discarded. You can pass function to useState which will only be executed once. Apparently based on the docs, useRef doesn't have such option. But you can simulate it:

const ref = useRef(null);

// ✅ IntersectionObserver is created lazily once
function getObserver() {
  if (ref.current === null) {
    ref.current = new IntersectionObserver(onIntersect);
  }
  return ref.current;
}
like image 183
Giorgi Moniava Avatar answered Sep 09 '25 22:09

Giorgi Moniava