React Hooks: useDims
Last updated on

React Hooks: useDims


Here’s another helpful React hook. This one returns the dimensions of an element that’s passed to it.

import { useState, useLayoutEffect } from "react";
function useDims(ref, isSvg = false) {
const [dim, setDim] = useState({
height: 0,
width: 0,
top: 0,
left: 0,
});
useLayoutEffect(() => {
if (ref && ref.current) {
if (isSvg) {
const { height, width, x, y } = ref.current.getBBox();
setDim({
height,
width,
top: y,
left: x,
});
} else {
setDim({
height: ref.current.offsetHeight,
width: ref.current.offsetWidth,
top: ref.current.offsetTop,
left: ref.current.offsetLeft,
});
}
}
}, [ref, isSvg]);
return dim;
}
export default useDims;

It can be used in a component like this.

import React from "react";
function Chart() {
const chartRef = React.useRef(null);
const { width, height, top, left } = useDims(chartRef);
return (
<div ref={chartRef}>
<ul>
<li>width: {width}</li>
<li>height: {height}</li>
<li>top: {top}</li>
<li>left: {left}</li>
</ul>
</div>
);
}

Let’s break it down a bit. We start by receiving a ref and an optional boolean of isSvg. Since svgs use a different function to calculate size we can use this flag to differentiate.

Our hook is using a default dimension object in state with all values set to zero. We then return that dim if there aren’t any changes.

function useDims(ref, isSvg = false) {
const [dim, setDim] = useState({
height: 0,
width: 0,
top: 0,
left: 0
});
{...}
return dim;

Next, we have useEffect which does the heavy lifting. We’re checking to see if we have a value in the ref and we are having useEffect watch the ref and isSvg.

useLayoutEffect(() => {
if (ref && ref.current) {
{...}
}
}, [ref, isSvg]);

Then, we have the calcs for the html and svg element. For the html element we can pull the offsets right off of the node. The svg, however, need to pass through getBBox() to get their dimensions.

if (isSvg) {
const { height, width, x, y } = ref.current.getBBox();
setDim({
height,
width,
top: y,
left: x,
});
} else {
setDim({
height: ref.current.offsetHeight,
width: ref.current.offsetWidth,
top: ref.current.offsetTop,
left: ref.current.offsetLeft,
});
}

Once it’s all together we have a quick way to grab the dimensions from elements. You can also use it for multiple elements in the same component.


Category: