MENU
Callback Ref
A callback ref (7.3) allows us to obtain the position and size of a DOM node. React will call that callback whenever the ref gets attached to a different node.
RESETRUNFULL
In this example, the callback ref will be called only when the component mounts and unmounts since the rendered <h1> component stays present throughout any rerenders. If you want to be notified any time a component resizes, you may want to use ResizeObserver or a third-party Hook built on it.
function MeasureExample() {
const [width, setWidth] = React.useState(0);
const measuredRef = React.useCallback(node => {
if (node !== null) {
setWidth(node.getBoundingClientRect().width);
}
}, []);
return (
<React.Fragment>
<h1 ref={measuredRef}>Hello, world</h1>
<h2>The above header is {Math.round(width)}px wide.</h2>
</React.Fragment >
);}
useRef is not used in the example above because an object ref doesn't notify us about changes to the current ref value. Using a callback ref ensures that even if a child component displays the measured node later (e.g. in response to a click), we still get notified about it in the parent component and can update the measurements:
This will result in a runtime error:<br> Uncaught TypeError: Cannot read property 'getBoundingClientRect' of null
RESETRUNFULL
RESETRUNFULL
function MeasureExample() {
const wRef = React.useRef(null);
return (
<React.Fragment>
<h1 ref={wRef}>Hello, world</h1>
<h2>The above header is
{Math.round(wRef.current.getBoundingClientRect().width)}px wide.</h2>
</React.Fragment >
);}ReactDOM.render(<MeasureExample/>,document.querySelector("div"));
We can extract the logic above into a reusable custom hook (Chapter 22):
RESETRUNFULL
function MeasureExample() {
const [rect, ref] = useClientRect();
return (
<React.Fragment>
<h1 ref={ref}>Hello, world</h1>
{rect !== null &&
<h2>The above header is {Math.round(rect.width)}px wide</h2>
}
</ React.Fragment >
);}function useClientRect() {
const [rect, setRect] = React.useState(null);
const ref = React.useCallback(node => {
if (node !== null) {
setRect(node.getBoundingClientRect());
}
}, []);
return [rect, ref];}