Reputation: 1387
Is it possible to detect when an element reference changes it's height? I tried using the following, but when the height of the element changes for whatever reason, the change is not detected. (Please consider that this must also work in IE11)
useEffect(() => {
// detect change in reference height
}, [elementRef])
Upvotes: 35
Views: 42727
Reputation: 11399
I noticed another answer mentioning to use a ResizeObserver, but the answer is incomplete, so I'd like to add my own.
You can create a ResizeObserver
inside a useEffect
-hook, and then do what you want to do when the element changes its size. Remember to disconnect from the resizeObserver
in the cleanup function.
useEffect(() => {
if (!elementRef.current) return;
const resizeObserver = new ResizeObserver(() => {
// Do what you want to do when the size of the element changes
});
resizeObserver.observe(elementRef.current);
return () => resizeObserver.disconnect(); // clean up
}, []);
As mentioned in the comments, it's also possible to use useCallback
instead of useEffect
.
You can create a ResizeObserver
inside a useCallback
-hook, and then do what you want to do when the element changes its size. React has an example on how to measure a DOM node.
const elementRef = useCallback(node => {
if (!node) return;
const resizeObserver = new ResizeObserver(() => {
// Do what you want to do when the size of the element changes
});
resizeObserver.observe(node);
}, []);
Upvotes: 58
Reputation: 2461
You could just use window
.
My example below is optimised with a cleanup removeEventListener
function should the component unmount.
const BoxAndHeight = () => {
const ref = React.useRef(null);
const [height, setHeight] = React.useState(0);
const onResize = React.useCallback(() => {
if (ref.current) setHeight(ref.current.clientHeight);
}, []);
React.useEffect(() => {
window.addEventListener("resize", onResize);
onResize();
return () => {
window.removeEventListener("resize", onResize);
};
}, []);
return (
<div ref={ref} style={style}>
<h1>My height: {height}</h1>
<p>
{dummyContent}
</p>
</div>
);
}
// Render it
ReactDOM.createRoot(
document.getElementById("root")
).render(<BoxAndHeight />);
const style = {
border: "2px solid #ccc",
padding: "10px",
backgroundColor: "#eee"
};
const dummyContent = "Lorem ipsum dolor sit, amet consectetur adipisicing elit. Distinctio, fugiat. Ex in neque velit perspiciatis recusandae, deleniti illum error ea distinctio obcaecati nisi deserunt ab unde corporis quas magnam quo cupiditate dolor dicta? Eos nostrum delectus suscipit! Hic corrupti, assumenda quo modi rem aperiam voluptas explicabo alias fuga error nulla. Eos tenetur voluptas repellat. Tempore, ab harum. Recusandae impedit adipisci soluta officia sunt quis voluptas, quae ea! Eveniet vero incidunt enim quod, voluptate fugiat maxime deserunt et laudantium quidem, ducimus sunt ratione voluptatem libero neque accusamus praesentium fugit doloremque est nisi excepturi. Quo inventore est soluta culpa quos? Minus, laudantium!";
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.1.0/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.1.0/umd/react-dom.development.js"></script>
Upvotes: 1
Reputation: 2822
The most efficient way is to use a resize observer.
You can set it up in a useEffect, and clear it when the component unmounts.
Upvotes: 4
Reputation: 475
I think you can use elementRef.current.clientHeight
in useEffect dependencies in order to listen to tag's height.
I test with this case and it worked.
function App() {
const tag = useRef();
const [height, setHeight] = useState(10);
useEffect(() => {
console.log("updated", tag?.current?.clientHeight);
}, [tag?.current?.clientHeight]);
useEffect(() => {
setInterval(() => {
setHeight((height) => height + 10);
console.log(height, tag.current.clientHeight);
}, 2000);
}, []);
return (
<div className="App" ref={tag}>
<div style={{ height: height, backgroundColor: "green" }}></div>
</div>
);
}
Here is the codesandbox https://codesandbox.io/embed/reactjs-playground-forked-b8j5n?fontsize=14&hidenavigation=1&theme=dark
Upvotes: -1