To get the width of a React element after render in React, we can combine two hooks: useRef()
and useEffect()
:
import React, { useEffect, useState, useRef } from 'react';
function ExampleComponent() {
const [width, setWidth] = useState(0);
const elementRef = useRef(null);
useEffect(() => {
setWidth(elementRef.current.offsetWidth);
}, []);
return (
<div ref={elementRef}>
{`The width of this element is: ${width}px`}
</div>
);
}
useEffect()
runs after the component mounts or re-renders, unlike useLayoutEffect()
that runs before. They both have a dependencies array that cause them to fire when any of those dependencies change.
We create a ref for the target element with useRef()
, and assign it to its ref
prop, so we can access the HTMLElement
object for this React element.
useRef
returns a mutable ref object that doesn’t change its value when a component is updated. Also, modifying the value of this object’s current
property does not cause a re-render. This is in contrast to the setState
update function returned from useState
.
We do use useState()
to create a state that we update when useEffect()
gets called. This update causes the component to update again from useEffect()
.
It’s also possible to get the width of the entire window in React, instead of just one element.
Get width of element with clientWidth
clientWidth
is another way to get the width of an element. Unlike offsetWidth
, it includes padding but excludes borders and scrollbars.
import React, { useRef, useLayoutEffect, useState } from 'react';
function ExampleComponent() {
const [width, setWidth] = useState(0);
const elementRef = useRef(null);
useEffect(() => {
setWidth(elementRef.current.clientWidth);
}, []);
return (
<div ref={elementRef}>
{`The width of this element is: ${width}px`}
<p>This element's width is measured using clientWidth.</p>
</div>
);
}
Get width of element after render and on resize in React
To get the width of an element after render and on resize:
- Combine the
useEffect()
anduseRef()
hooks to get the element’s width before it renders, like in the previous section. - Track the current width with state.
- Add a
resize
event listener to thewindow
object inuseEffect()
. - In the event listener, get the new width of the element, and update the state with it.
import React, { useLayoutEffect, useState, useRef } from 'react';
function ExampleComponent() {
const [width, setWidth] = useState(0);
const elementRef = useRef(null);
useEffect(() => {
const handleResize = () => {
setWidth(elementRef.current.offsetWidth);
};
handleResize();
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
}
}, []);
return (
<div ref={elementRef}>
{`The width of this element is: ${width}px`}
</div>
);
}
We call addEventListener()
in useEffect()
to set the resize
event listener on the element before it renders on the screen.
The resize
event listener is called whenever the user resizes the window. In the listener, we update the state that stores the element’s width, and this causes a re-render.
We call removeEventListener()
in useEffect
‘s clean-up function to stop listening for resize
events when the component is unmounted or when the dependencies change to prevent memory leaks and unintended side effects.
Get width of element before render in React
To get the width and height of an element before render in React, we can combine two React hooks: useRef
and useLayoutEffect
.
import React, { useRef, useLayoutEffect, useState } from 'react';
function ExampleComponent() {
const [width, setWidth] = useState(0);
const elementRef = useRef(null);
useLayoutEffect(() => {
setWidth(elementRef.current.offsetWidth);
}, []);
return (
<div ref={elementRef}>
{`The width of this element is: ${width}px`}
</div>
);
}
So the difference between “before render” and “after render” is useLayoutEffect()
and useEffect()
.
useLayoutEffect()
works just like useEffect()
, but the key difference is that it fires before the browser repaints the screen – before React renders the component.
We pass an empty dependencies array to useLayoutEffect()
to make sure it only gets called once.
Here we create a ref for the target element with useRef()
, and assign it to its ref
prop, so we can access the HTMLElement
object for this React element.
useRef
returns a mutable ref object that doesn’t change its value when a component is updated. Also, modifying the value of this object’s current
property does not cause a re-render. This is in contrast to the setState
update function returned from useState
.
We do use useState()
though, to create a state that we update when useLayoutEffect()
gets called. So calling setWidth()
will cause the component to be re-rendered.
To get the actual width, we use the offsetWidth
property which includes borders, padding, and any scrollbars when calculating the element’s width.
Get width of element before render and on resize in React
To get the width of an element before render and also on resize:
- Combine the
useLayoutEffect()
anduseRef()
hooks to get the element’s width before it renders, like in the previous section. - Track the current width with state.
- Add a
resize
event listener to thewindow
object inuseLayoutEffect()
. - In the event listener, get the new width of the element, and update the state with it.
import React, { useLayoutEffect, useState, useRef } from 'react';
function ExampleComponent() {
const [width, setWidth] = useState(0);
const elementRef = useRef(null);
useLayoutEffect(() => {
const handleResize = () => {
setWidth(elementRef.current.offsetWidth);
};
handleResize();
window.addEventListener('resize', handleResize);
return () => {
window.removeEventListener('resize', handleResize);
}
}, []);
return (
<div ref={elementRef}>
{`The width of this element is: ${width}px`}
</div>
);
}
We call addEventListener()
in useLayoutEffect()
to set the resize
event listener on the element before it renders on the screen.
The resize
event listener is called whenever the user resizes the window. In the listener, we update the state that stores the element’s width, and this causes a re-render.
We call removeEventListener()
in useLayoutEffect
‘s clean-up function, to stop listening for resize
events when the component is unmounted or when the dependencies change, to prevent memory leaks and unintended side effects.
Key takeaways
- To get the width of a React element after it renders, we can combine the
useRef()
anduseEffect()
hooks. - The
offsetWidth
property includes borders, padding, and scrollbars, whileclientWidth
includes padding only. - To get the width of an element before render, use
useLayoutEffect()
instead ofuseEffect()
. - To get the width of an element on resize, add a
resize
event listener to the window object inuseEffect()
oruseLayoutEffect()
.
Every Crazy Thing JavaScript Does
A captivating guide to the subtle caveats and lesser-known parts of JavaScript.