How to listen to "ref" object changes?

Viewed 4466

Consider following example. I have a ref of a div and I want to pass this ref to Child. BUT if I just use it as it is right now, the Child is not re-rendered when the ref object updates and stores the proper HTML element.

I can make a fix for it and use the callback approach with useCallback. Just uncomment the commented line and see that then it works properly (both solutions) because parent re-renders due to state update so the correct ref is passed also from the first approach.

QUESTION: Is there a way to AVOID using state and somehow let Child know that ref object updated in the parent?

Note: I know I can use useEffect in Child and listen to the someRef changes but I want to have access to the someRef object in the function body, not only within the hook body.

const { useState, useRef, useCallback } = React;

const Child = ({ someRef, node }) => {
  console.log(someRef, node); // someRef is always null and doesnt update...

  return null;
}

const App = () => {
  /* 1st approach */
  const someRef = useRef(null);
  
  /* 2nd approach */
  const [node, setNode] = useState(null);
  
  const someRef2 = useCallback(n => {
    if (n !== null) {
        // setNode(n)   <----- uncomment to see it works
    }
  }, []);
  
  return (
     <div>
      <div ref={someRef}>text1</div>
      <div ref={someRef2}>text2</div>
      <Child someRef={someRef} node={node} />
     </div>
  );
};

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

1 Answers

No, as far as I know, there is no way to subscribe / be notified on ref changes.

From React docs on useRef:

Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.

At the end of the day, your app will have to respond to changes in state. Either the parent's or own child state.

You even might update the ref during the render phase of the parent so it will be kept "in sync" with any state changes on the parent. But after all what will trigger updates is the state change, and not the ref's.

Related