title: Infinite scroll with useEffect hooks run with previous argument value
body: <p>I implemented the following infinite scroll solution. It's not (yet) optimized for 10K+ items, so thats out of scope for my question.</p>
  <p>There are essentially 3 conditions/cases that trigger a <code>fetchMessage()</code>:</p>
  <ol>
  <li>Initial load, no data in the Redux store</li>
  <li>User scrolls and reaches the 80% of the page height</li>
  <li>Initial load happens but height is loaded content is not enough to reach 80% of the height / make a scrollbar appear so user scrolling is impossible (therefore we can't see the next page of results)</li>
  </ol>
  <p>Questions: What are the standard non-js industry solutions for case (3) (I guess forcing a min-height with CSS)</p>
  <p>Bug: <code>fetchMessage()</code> is run two times with the same <code>page</code> resulting in duplicate data loaded.</p>
  <pre class="lang-js prettyprint-override"><code>const message = useSelector((state) =&gt; selectMessages(state)); // returns an array of objects to display
  const page = useSelector((state) =&gt; selectPage(state)); // returns current page of results
  const totalPages = useSelector((state) =&gt; selectTotalNumberPages(state)); // returns total number of result pages
  const isFetching = useSelector((state) =&gt; selectIsFetching(state)); // boolean set to true when a fetch is triggered and to false when its complete
  
  const fetchMessage = useCallback(() =&gt; {
      console.log(&quot;component page:&quot;, page);
      return dispatch(getMessagesIfNeeded(page));
    }, [dispatch, page]);
  
    const handleScroll = throttle(() =&gt; {
      console.log(&quot;scrolled&quot;);
      let d = document.body;
      let scrollTop = window.scrollY;
      let windowHeight =
        window.innerHeight || document.documentElement.clientHeight;
      let height = d.offsetHeight - windowHeight;
      let scrollPercentage = scrollTop / height;
      if (scrollPercentage &gt; 0.8) {
        if (!isFetching &amp;&amp; page &lt;= totalPages) {
          fetchMessage();
        }
      }
    }, 1000);
  
    useEffect(() =&gt; {
      window.addEventListener(&quot;scroll&quot;, handleScroll);
      return function cleanup() {
        window.removeEventListener(&quot;scroll&quot;, handleScroll);
      };
    });
  
    useEffect(() =&gt; {
      if (!message.length) {
        fetchMessage();
      }
    }, [fetchMessage, message]);
  
    useEffect(() =&gt; {
      const d = document.body;
      const bodyHeight = d.offsetHeight;
      let windowHeight =
        window.innerHeight || document.documentElement.clientHeight;
      if (windowHeight - bodyHeight &gt; 200 &amp;&amp; !isFetching &amp;&amp; page &lt;= totalPages) {
        fetchMessage();
      }
    }, [isFetching, fetchMessage, page, totalPages]);
  </code></pre>
  <p>I also have a working version of the issue: <a href="https://codesandbox.io/s/recursing-noether-npp31?file=/src/message/MessageList.jsx" rel="nofollow noreferrer">https://codesandbox.io/s/recursing-noether-npp31?file=/src/message/MessageList.jsx</a></p>