useEffect.dev
← Back to lessons

Lesson 12. Custom hooks to use the browser’s APIs 4. Exercise: Get an element’s size

The hook useElementSize can return many values when the element is resized; can you make it debounce the returned values, as we saw in Lesson 9, to get a new value only every 300 milliseconds?

Result
Click here to see the solution!
const useElementSize = (elementRef, debounceDelayMs = 300) => {
const [size, setSize] = useState([undefined, undefined])
const [debouncedSize, setDebouncedSize] = useState(size)
const timeoutRef = useRef(null)
useEffect(() => {
if (!timeoutRef.current) {
timeoutRef.current = setTimeout(() => {
setDebouncedSize(size)
timeoutRef.current = null
}, 300)
}
}, [size])
useEffect(() => {
return () => {
if (timeoutRef.current) {
clearTimeout(timeoutRef.current)
}
}
}, [])
useEffect(() => {
const resizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
if (entry.contentRect) {
setSize([entry.contentRect.width, entry.contentRect.height])
}
}
})
resizeObserver.observe(elementRef.current)
return () => {
resizeObserver.disconnect()
}
}, [elementRef])
return debouncedSize
}