mantinedev / mantine

A fully featured React components library
https://mantine.dev
MIT License
26.3k stars 1.86k forks source link

Bug: Changing element breaks use-in-viewport hook #6812

Open fellmann opened 2 weeks ago

fellmann commented 2 weeks ago

Dependencies check up

What version of @mantine/* packages do you have in package.json?

7.12.2

What package has an issue?

@mantine/hooks

What framework do you use?

Vite

In which browsers you can reproduce the issue?

All

Describe the bug

The use-in-viewport hook does not react to changes of the ref. If the observed element changes, it stops working.

If possible, include a link to a codesandbox with a minimal reproduction

https://codesandbox.io/p/sandbox/mantine-react-template-forked-nlnrm7

Possible fix

After some problems especially in StrictMode / Dev, I found a simple but working solution:

import { useCallback, useRef, useState } from "react";

export function useInViewport<T extends HTMLElement>() {
  const observer = useRef<IntersectionObserver | null>(null);
  const [inViewport, setInViewport] = useState(false);

  const ref = useCallback((node: T | null) => {
    if (typeof IntersectionObserver !== "undefined") {
      if (node && !observer.current) {
        observer.current = new IntersectionObserver(([entry]) =>
          setInViewport(entry.isIntersecting)
        );
      } else {
        observer.current?.disconnect();
      }

      if (node) {
        observer.current?.observe(node);
      } else {
        setInViewport(false);
      }
    }
  }, []);

  return { ref, inViewport };
}

Self-service

ashar-nadeem-lumi commented 12 hours ago

@fellmann Thanks for the fixed code, made a custom hook and this works great now. Would be nice to have this fix merged in, definitely wasted a lot of time on this bug