Darren
Darren

Reputation: 2290

Unobserve IntersectionObserver in React.useEffect

I am trying to get the top and bottom measurements from multiple elements by using IntersectionObserver. However, once I have the measurements, how can I unobserve the elements.

The problem is that each element is position: sticky and when scrolling additional values are added to the array and I only want the measurements from the initial render.

const observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      const measurement = {
        top: entry.boundingClientRect.top,
        bottom: entry.boundingClientRect.bottom,
      };
      console.log(measurement);
    });
  });

  useEffect(() => {
    const sections = document.querySelectorAll(`section#dark`)
    sections.forEach((section) => observer.observe(section));
    return () => {
      // observer.disconnect(); removed in Stackoverflow edit
      sections.forEach(section => observer.observe(section)); // Added in Stackoverflow edit
    };
  }, []);

I have tried using observer.unobserve() but cannot figure out what value it requires as it returns an error of Argument of type 'NodeListOf<Element>' is not assignable to parameter of type 'Element'.

EDIT: I figured out how to use oberver.unobserve with sections.forEach(section => observer.unobserve(section)); but it still adds more records when scrolling.

Full example can be seen here StackBlitz

Upvotes: 4

Views: 2410

Answers (1)

lissettdm
lissettdm

Reputation: 13078

You need to move the observer instance to useEffect block because every time your component is updated a new IntersectionObserver instance is created:

useEffect(() => {
  const observer = new IntersectionObserver((entries) => {
      entries.forEach((entry) => {
      const measurement = {
        top: entry.boundingClientRect.top,
        bottom: entry.boundingClientRect.bottom,
      };
      console.log(measurement);
      observer.unobserve(entry.target); //<-- call unobserve here
      });
    });
  const sections = document.querySelectorAll(`section#dark`)
  sections.forEach((section) => observer.observe(section));
  return () => {
     observer.disconnect();
  };
}, []);

Upvotes: 5

Related Questions