intersection observer hook

by gbos

HTML

<div id="app"></div>

CSS

body {
  background: white;
  padding: 20px;
  font-family: Arial;
}

React

const { useEffect, useState, useRef } = React;


const isIntersectionObserverSupported = 'IntersectionObserver' in window;

function useIsVisible () {
  const [isVisible, setIsVisible] = useState(false);
  const [hasBeenVisible, setHasBeenVisible] = useState(false);
  const observerRef = useRef(null);
  const ref = useRef(null);

  useEffect(() => {
    observerRef.current = new IntersectionObserver(([entry]) =>
      setIsVisible(entry.isIntersecting)
    );
  }, []);
  
  useEffect(() => {
  	if (isVisible && !hasBeenVisible) {
    	setHasBeenVisible(true);
    }
  }, [isVisible]);

  useEffect(() => {
    observerRef.current.observe(ref.current);
    return () => {
      observerRef.current.disconnect();
    };
  }, [ref]);

  return {isVisible, hasBeenVisible, ref};
}

function Component ({index}) {
	const {ref, isVisible, hasBeenVisible} = useIsVisible();
    useEffect(() => {
    	console.log(`index ${index} visible: ${isVisible} ${hasBeenVisible}`);
    }, [isVisible, hasBeenVisible]);
    return <div style={{height: '60vh', backgroundColor: 'lightgrey', marginBottom: '10px', fontSize: '40px'}} ref={ref}>{index}</div>;
}


function App () {
return <div>
    <Component index="aa"/>
    <Component index="bb"/>
    <Component index="cc"/>
    <Component index="dd"/>
    <Component index="ee"/>

</div>;
}


ReactDOM.render(<App />, document.querySelector("#app"))