Let’s say I have a component:
function Component({ children }) {
const ref = useRef(null);
useEffect(() => {
// do something based on ref.current size
}, [])
return <div ref={ref}>{children}</div>;
}
I would like to do something based on the change of the size of the div. The size will change when the children changes. However, with the currect code, useEffect will only fire once and won’t react to children change.
I can’t put ref in the dependencies array as this won’t retrigger useEffect.
useEffect(() => {
// no effect
}, [ref]);
I could put children in the array but this smells wrong – it’s definitely an antipattern.
useEffect(() => {
// works but blah
}, [children]);
What would be the idiomatic react way to handle this case?
>Solution :
In order to trigger the useEffect when the size of the div changes due to a change in children, you can use the ResizeObserver API to observe changes in the size of the div element.
Here’s an example implementation:
import { useRef, useEffect } from 'react';
function Component({ children }) {
const divRef = useRef(null);
useEffect(() => {
const observer = new ResizeObserver(entries => {
// do something when size changes
});
observer.observe(divRef.current);
return () => observer.disconnect();
}, [divRef]);
return <div ref={divRef}>{children}</div>;
}
In this implementation, we create a ResizeObserver object in the useEffect hook and use it to observe changes to the size of the div element referenced by the divRef ref. When a change is detected, the function passed to the ResizeObserver constructor is called with an array of ResizeObserverEntry objects containing information about the changes. You can then update your component state or do any other necessary side effects based on this information.
By using the divRef as the dependency array for useEffect, we ensure that the observer is set up and torn down correctly when the div element is mounted and unmounted, and that the observer is also updated when the divRef ref is updated due to a change in the children prop.