3

Following is the sample example I was trying to understand intersection observer:

function Test(props) {
  const loadingRef = useRef(null);
  useEffect(() => {
    let options = {
      root: null,
      rootMargin: '0px',
      threshold: 1.0
    }
    let observer = new IntersectionObserver(handleIntersection, options);
    observer.observe(loadingRef.current)
  }, [])

  function handleIntersection(x, y) {
    console.log("Why this triggers on component mount?");
  }
  return (
    <div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div style={{width: '100%', height: '100px', background: '#c4c4c4', borderBottom: '1px solid #f4f4f4'}}></div>
      <div ref={loadingRef}></div>
    </div>
  );
}

I can't understand as to why this triggers on component mount even when target element doesn't intersect with the source element.

johnnash
  • 424
  • 2
  • 8
  • 17
  • 1
    Hi, johnnash - were you ever able to figure this one out? I am having the same issue in my component and not sure why. The intersection observer fires when the component mounts, and then again when it is visible. I'm trying to figure out why? – Maiya Jul 10 '20 at 04:57
  • @Maiya, same question for you. I'm stuck... – Itay Ganor Apr 09 '21 at 11:57
  • @ItayGanor I think this is expected behavior actually, but maybe just add a "let didIntersectionObserverFire = false." Then, change the variable to true in the intersection observer callback. And only run your code if it is set to true; – Maiya May 15 '21 at 15:47

2 Answers2

0

Your useEffect has a second argument:

useEffect(() => {
  let options = {
    root: null,
    rootMargin: '0px',
    threshold: 1.0
  }
  let observer = new IntersectionObserver(handleIntersection, options);
  observer.observe(loadingRef.current)
}, [])

   ^^
   ||

These here.

This means that it is run when the component mounts. There is a part of the Hooks FAQ on reactjs.org that mentions this.

rrd
  • 5,789
  • 3
  • 28
  • 36
  • 1
    Yes, I know this is similar to componentDidMount but my question pertains to intersection observer.Why does it trigger when loadingRef div has not intersected with the root. – johnnash Sep 04 '19 at 08:26
  • But the triggering has nothing to do with intersection observer, but rather your use of useEffect()'s second argument. Your question asks literally that: I can't understand as to why this triggers on component mount ... – rrd Sep 04 '19 at 08:29
0

It is an old thread but I'm just pasting the solution that worked for me, because it was the only question asked the same I wanted to resolve.

So, at fisrt the condition entry.isIntersecting is true because the children are not rendered yet and the div element is intersecting.

When the children render the observer propagates again but this time without entry.isIntersecting set to true because div is not part of the viewport anymore.

I use hooks and my Effect looks like this.

useEffect(() => {
  const currentRef = loader.current
  const observer = new IntersectionObserver(
  ([entry]) => {
    if (entry.isIntersecting && iterationRef.current > 0) {
      onScrollEnd && onScrollEnd(iterationRef.current)
    } else if (entry.isIntersecting) {
      iterationRef.current = iterationRef.current + 1
    }
  },
  {
    root: parent.current,
    rootMargin: '0px',
    threshold: 1.0,
  }
)
if (currentRef) {
  observer.observe(currentRef)
}
return () => {
  if (currentRef) {
    observer.unobserve(currentRef)
  }
}
}, [onScrollEnd])
thandem
  • 175
  • 1
  • 2
  • 11