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?
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.
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.
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.
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.
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:
node = <h1>Hello, world</h1>
: Initial Render, Ref assignmentFor 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.
node = <h1>Hello, world</h1>
: now with DOM elementUPDATE (for the last render #6):
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With