1

We have some components that we want to render only once they are visible. Once rendered we do not want them to be invisible again.

What is the best way to do this with react-intersection-observer (without creating additional divs) ?

ic3
  • 7,917
  • 14
  • 67
  • 115

3 Answers3

1

Use the triggerOnce option to avoid tracking the visibility state after the 1st change:

const { ref, inView } = useInView({
  threshold: 0,
  triggerOnce: true
});
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • thanks, it's not working for us an all scenarios. It's not clear way but doing our own implementation works and with the new javascript IntersectionObserver it's a few lines of code – ic3 Mar 08 '23 at 07:49
0

It's not working an all scenarios so we implemented our own hook using IntersectionObserver :

// should not be the case on modern browsers
const hasIntersectionObserver: boolean = 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window
       && 'isIntersecting' in window.IntersectionObserverEntry.prototype;

/**
/* returns [ref,isVisible]
/* ref is to be used in the element we want to check visibility
/* i.e :  <div ref={ref} />
**/
export function useOnWhenVisible(alwaysVisible: boolean): [(el: Element) => void, boolean] {

    const [ref, setRef] = useState<Element>();
    const [isVisible, setIsVisible] = useState<boolean>(alwaysVisible || !hasIntersectionObserver);

    useEffect(() => {

        // it's just done once
        if (ref == null || isVisible) {
            return undefined;
        }

        const observer = new IntersectionObserver(([entry]) => {
            if (entry.isIntersecting) {
                setIsVisible(true)
            }
        });

        observer.observe(ref);
        return () => {
            observer.disconnect();
        }

    }, [setIsVisible, ref, isVisible]);


    return [setRef, isVisible];
}
ic3
  • 7,917
  • 14
  • 67
  • 115
0

A few days ago, I encountered a similar problem, but have not yet solved it.
In the library I used (preact-intersection-observer).
there are several options:
rootMargin,
threshold,
defaultInView,
triggerOnce

but the main problem arose when re-rendering the elements.
When the site loaded for the first time, everything worked fine,
but after clicking on the cart icon, or login,
the page was rerendered,
and it seems that the observer did not track further actions, although it writes when the button is clicked that the ref.current is equal to the correct div.
But at the same time, I see a small strip 22px high,
maybe it's the async lazy preact that doesn't load the component.
If we change triggerOnce on false, all works fine, but we also see permanent trigering on off mounted components.
Maybe problem in that part of code:

  // If window is defined, and the observer isn't defined
  if (!!window && !observer.current) {
    observer.current = new IntersectionObserver(
      (entries) => {
        entry.current = entries[0];
        setInView(entries[0].isIntersecting);
      },
      {
        ...options,
        root: ref.current,
      }
    );
  }