Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is a React Ref callback (as an arrow function or inline function) called multiple times on initial page load?

Please refer to this URL in the React DOCS. A version of this code is also available here.

I understand that inside a Functional React Component, it is preferred to use the useCallback hook to create a ref callback as shown in the React Docs URL above, but I wanted to understand what would happen if, instead, a simple arrow function ( inline function ) is used as a ref callback.

So, below, I have modified the code from the above URL to not use the useCallback hook. Instead, I am just using a regular arrow function as a ref callback. Additionally, I have added two console.log statements. Here is the code which is also available at this URL.

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

import "./styles.css";

function App() {
  const [height, setHeight] = useState(0);

  const measuredRef = node => {
    console.log("Setting height. node = ", node);
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);
    }
  };

  console.log("Rendering.");
  return (
    <div className="App">
      <h1 ref={measuredRef}>Hello, world</h1>
      <h2>The above header is {Math.round(height)}px tall</h2>
    </div>
  );
}

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

On loading this app, the following are printed (with numbering added):

  1. Rendering.
  2. Setting height. node =  <h1>Hello, world</h1> 
  3. Rendering.
  4. Setting height. node =  null
  5. Setting height. node =  <h1>Hello, world</h1>
  6. Rendering.

Why is the ref callback called three times and why does the component render three times on initial load?

like image 650
Alan C. S. Avatar asked Sep 27 '19 01:09

Alan C. S.


People also ask

Why are inline ref callback or function not recommended?

If the ref callback is defined as an inline function, it will get called twice during updates, first with null and then again with the DOM element. This is because a new instance of the function is created with each render, so React needs to clear the old ref and set up the new one.

What is callback REF IN React?

React will call the ref callback with the DOM element when the component mounts, and call it with null when it unmounts. Refs are guaranteed to be up-to-date before componentDidMount or componentDidUpdate fires. You can pass callback refs between components like you can with object refs that were created with React.

Why we should not use REF IN React?

It is a general rule of thumb to avoid using refs unless you absolutely have to. The official React documentation outlined only three possible use cases where refs are entirely considered useful for lack of better alternatives: Managing focus, text selection, or media playback. Triggering imperative animations.

How does Ref work React?

Refs are a function provided by React to access the DOM element and the React element that you might have created on your own. They are used in cases where we want to change the value of a child component, without making use of props and all.


1 Answers

Why is the ref callback called three times and why does the component render three times on initial load?

Mainly because inside your callback ref, measuredRef(), you're doing a state update via setHeight().

Here's a step-by-step explanation:

  1. Rendering: Initial Render
  2. Setting height node = <h1>Hello, world</h1>: Initial Render, Ref assignment
  3. Rendering.: Component Re-render due to set height

For the last two prints, refer to caveats of callback refs:

If the ref callback is defined as an inline function, it will get called twice during updates, first with null and then again with the DOM element.

  1. Setting height. node = null: null due to height update
  2. Setting height. node = <h1>Hello, world</h1>: now with DOM element

UPDATE (for the last render #6):

  1. The last render was due to #5 where node != null. So setHeight was called.

i.e #4 (node = null) doesn't cause a re-render cause height is only set if node != null.

like image 192
Joseph D. Avatar answered Sep 29 '22 09:09

Joseph D.