title: Simple Carousel in React - How to register Scrolling to next Slide?
body: <p>This is a relatively simple problem, but I haven't been able to solve it. I have built the following carousel / slider:</p>
  
  <pre><code>const BlogPostCardSlider = ({ children }) =&gt; {
    const [activeSlide, setActiveSlide] = useState(0);
    const activeSlideRef = useRef(null);
    const wrapperRef = useRef(null);
    const firstRenderRef = useRef(true);
  
    useEffect(() =&gt; {
      if (firstRenderRef.current) {
        //this is checking whether its the first render of the component. If it is, we dont want useEffect to run.
        firstRenderRef.current = false;
      } else if (activeSlideRef.current) {
        activeSlideRef.current.scrollIntoView({
          behavior: 'smooth',
          block: 'nearest',
          inline: 'nearest'
        });
      }
    }, [activeSlide]);
  
    const moveRight = () =&gt; {
      if (activeSlide + 1 &gt;= children.length) {
        return children.length - 1;
      }
      return activeSlide + 1;
    };
  
    const moveLeft = () =&gt; {
      if (activeSlide - 1 &lt;= 0) {
        return 0;
      }
      return activeSlide - 1;
    };
  
    return (
      &lt;div id="trap" tabIndex="0"&gt;
        &lt;button onClick={() =&gt; setActiveSlide(moveLeft)}&gt;PREV&lt;/button&gt;
  
        {children.map((child, i) =&gt; {
          return (
            &lt;SlideLink
              key={`slideLink-${i}`}
              isActive={activeSlide === i}
              onClick={e =&gt; {
                setActiveSlide(i);
              }}
            &gt;
              {i + 1}
            &lt;/SlideLink&gt;
          );
        })}
  
        &lt;Wrapper
          onScroll={e =&gt; {
            let { width } = wrapperRef.current.getBoundingClientRect();
            let { scrollLeft } = wrapperRef.current;
  
            if ((scrollLeft / width) % 1 === 0) {
              setActiveSlide(scrollLeft / width);
            }
          }}
          ref={wrapperRef}
        &gt;
          {children.map((child, i) =&gt; {
            return (
              &lt;Slide
                key={`slide-${i}`}
                ref={i === activeSlide ? activeSlideRef : null}
              &gt;
                {child}
              &lt;/Slide&gt;
            );
          })}
        &lt;/Wrapper&gt;
  
        &lt;button onClick={() =&gt; setActiveSlide(moveRight)}&gt;NEXT&lt;/button&gt;
      &lt;/div&gt;
    );
  };
  
  export default BlogPostCardSlider;
  </code></pre>
  
  <p>It displays its children as Slides in a carousel. You can navigate the carousel by pressing the 'NEXT' or 'PREVIOUS' buttons. There is also a component that shows you what slide you're on (e.g.: <code>1 2 *3* 4</code> etc.). I call these the <code>SlideLink(s)</code>. Whenever the <code>activeSlide</code> updates, the SlideLink will update and highlight you the new current Slide. </p>
  
  <p>Lastly, you can also navigate by scrolling. <strong>And here's the problem</strong>:</p>
  
  <p>Whenever somebody scrolls, I am checking what slide they're on by doing some calculations:</p>
  
  <pre><code>onScroll={e =&gt; {
            let { width } = wrapperRef.current.getBoundingClientRect();
            let { scrollLeft } = wrapperRef.current;
  
            if ((scrollLeft / width) % 1 === 0) {
              setActiveSlide(scrollLeft / width);
            }
          }}
  </code></pre>
  
  <p>...the result of this is that <code>setActiveSlide</code> <strong>is only called once the slide completely in view.</strong> This results in a laggy experience : the user has scrolled to the next slide, the next slide is in view, but the calculation is not completed yet (since it is only completed once the Slide is 100% in view), so the active SlideLink gets updated very late in the process.</p>
  
  <p>How would I solve this? Is there some way to optimistically update this?</p>