Next.js Discord

Discord Forum

Observing Next Images loaded asynchronously with ResizeObserver API

Answered
Californian posted this in #help-forum
Open in Discord
Avatar
CalifornianOP
I'm using ResizeObserver API to observe, inside an useEffect hook, a bunch of references to Next Image elements which are loaded asynchronously into component states in another useEffect hook.

- Problem: if I observe before the images are loaded into the states, the observer callback can't recognize the references.

- Work Around: observe only after a few miliseconds.

Is there a better solution ?
Answered by Ray
  useEffect(() => {
    if (!imageState) return;
    const resizeObserver = new ResizeObserver(() => {
      // Do what you want to do when the size of the element changes
    });
    resizeObserver.observe(ref.current);
    return () => resizeObserver.disconnect();
  }, [imageState]);
View full answer

6 Replies

Avatar
Ray
try this?

  const ref = useRef<HTMLImageElement>(null);

  useEffect(() => {
    if (!ref.current?.complete) return;
    const resizeObserver = new ResizeObserver(() => {
      // Do what you want to do when the size of the element changes
    });
    resizeObserver.observe(ref.current);
    return () => resizeObserver.disconnect();
  }, []);

  return (
    <>
      <Image ref={ref} src="" alt="" />
    </>
   )
Avatar
CalifornianOP
This was what I first did, but actually in my case the Image is loaded asynchronously by another function, inside another useEffect hook. So, the observer can't observe it at this moment. My work around is something like:

  const ref = useRef<HTMLImageElement>(null);
  const [imageState, setImageState] = useState<ImageInterface>(null);
  
  useEffect(() => {
    const imageData = await imageLoader(...);
    setImageState(imageDate);
  }, []);

  useEffect(() => {
    if (!ref.current?.complete) return;
    const resizeObserver = new ResizeObserver(() => {
      // Do what you want to do when the size of the element changes
    });
    setTimeout(() => {resizeObserver.observe(ref.current);}, 200);
    return () => resizeObserver.disconnect();
  }, []);

  return (
    <>
      <Image ref={ref} src=imageState.src width=imageState.width height=imageState.height alt="" />
    </>
   )


I'm wondering if there is something better than this imprecise setTimeout strategy.
Avatar
Ray
if (!imageState) return
how about this?
setTimeout is not a good solution for slow network speed lol
Avatar
Ray
  useEffect(() => {
    if (!imageState) return;
    const resizeObserver = new ResizeObserver(() => {
      // Do what you want to do when the size of the element changes
    });
    resizeObserver.observe(ref.current);
    return () => resizeObserver.disconnect();
  }, [imageState]);
Answer
Avatar
CalifornianOP
Ah, good idea that of binding the imageState to the useEffect hook. Thanks, this works !