title: Problem with intersection oberserver api / useEffect hook triggering callback twice
body: <p>I'm not exactly certain why but something i've done is causing the callback in my intersectionObserver instance to fire 2 times when it should only fire 1 time.
  any insights as to why that might be would be greatly appreciated.</p>
  
  <p>amongst other things happening in this component, I'm trying to set up insersectionObserver to observe an element i'vecalled bottom-boundary, by calling the observe method on my observer instance inside a useEffect() hook. this works fine, except that the observer fires my callback twice. I've tried adding the observer to the dependancy array, and I've tried adding getEvents to the dependancy array, but I just an infinite loop instead of a double fire.</p>
  
  <pre><code>import React, { useState, useEffect, useReducer } from 'react';
  import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
  import CreatePromo from './components/promo/CreatePromo';
  import MainStyle from './components/MainStyle';
  import Home from './components/Home';
  import SearchEvents from './components/SearchEvents';
  import Social from './components/Social';
  import SimpleExample from './components/EventLocationMap';
  import PromoState from './components/context/PromoContext/PromoState';
  import './tailwind.generated.css';
  import 'react-quill/dist/quill.snow.css';
  import './App.css';
  // @TODO start using context api for global state management ASAP.
  
  const App = () =&gt; {
    //set initial createPromo widget state.
    const [allEvents, setAllEvents] = useState([]);
    const [promoState, setPromoState] = useState({
      name: '',
      type: '',
      startDate: '',
      startTime: '',
      endDate: '',
      endTime: '',
      address: '',
      city: '',
      state: '',
      postal: '',
      description: '',
      pictures: '',
      files: null,
    });
  
    // options for the IntersectionObserver constructor below
    let options = {
      root: null,
      rootMargin: '0px',
      threshold: 1.0,
    };
  
    let eventsToShow = 0;
  
    // instantiate intersection observer.
    const observer = new IntersectionObserver((entries) =&gt; {
      entries.forEach((entry) =&gt; {
        console.log(entry);
        console.log(entry.isIntersecting);
      });
      eventsToShow += 4;
      console.log('trigger');
      getEvents(eventsToShow);
    }, options);
  
    //defines our backend api call to get events
    const getEvents = async (numberOfEvents) =&gt; {
      try {
        const events = await fetch(
          `http://localhost:3001/api/events/${numberOfEvents}`
        );
        const newData = await events.json();
        setAllEvents([...allEvents, ...newData]);
        return newData;
      } catch (error) {
        console.log(error);
      }
    };
  
    //wrapper function to add a new event to allEvents
    const handleSetAllEvents = (newEvent) =&gt; {
      setAllEvents([...allEvents, newEvent]);
    };
  
    //wrapper function for updating controlled form state
    const handlePromoStateChange = (e) =&gt; {
      setPromoState({ ...promoState, [e.target.name]: e.target.value });
    };
  
    //wrapper function for handling the react-quill rich-text input specifically
    const handleDescriptionChange = (value) =&gt;
      setPromoState({ ...promoState, description: value });
  
    useEffect(() =&gt; {
      //loads more events when viewport intersects with #bottom-boundary
      observer.observe(document.querySelector('#bottom-boundary'));
    }, []);
  
    return (
      // &lt;PromoState&gt;
      &lt;Router&gt;
        &lt;MainStyle&gt;
          &lt;Switch&gt;
            &lt;Route exact path='/'&gt;
              &lt;Home allEvents={allEvents} /&gt;
            &lt;/Route&gt;
            &lt;Route exact path='/create'&gt;
              &lt;CreatePromo
                promoState={promoState}
                handlePromoStateChange={handlePromoStateChange}
                handleDescriptionChange={handleDescriptionChange}
                handleSetAllEvents={handleSetAllEvents}
              /&gt;
            &lt;/Route&gt;
            &lt;Route path='/search'&gt;
              &lt;SearchEvents /&gt;
            &lt;/Route&gt;
            &lt;Route path='/social'&gt;
              &lt;Social /&gt;
            &lt;/Route&gt;
          &lt;/Switch&gt;
        &lt;/MainStyle&gt;
      &lt;/Router&gt;
      // &lt;/PromoState&gt;
    );
  };
  
  export default App;
  </code></pre>