Search code examples
reactjscarouselrequestanimationframe

React JS window.requestAnimationFrame(update)


I am using Flickity plugin on React JS and all works. However, I want to create slider like https://brand.uber.com (Best-in-class examples section).

The workaround example posted at https://github.com/metafizzy/flickity/issues/77 works, but i have issue with play and pause functions.

The issues is window.requestAnimationFrame(update); is re rendering component before pause is taken into account. I have tried with local state and also redux, but it re-renders before i can dispatch. I am using function comp and code below.

 const carouselIsScrolling = useSelector(isServicesScrolling);
  const servicesCategoriesSel = useSelector(getServiceCategories);
  const carousel = useRef(null);
  const dispatch = useDispatch();

  const update = () => {

    if (carousel.current.flkty.slides && carouselIsScrolling) {
      carousel.current.flkty.x =
        (carousel.current.flkty.x - tickerSpeed) %
        carousel.current.flkty.slideableWidth;
      carousel.current.flkty.selectedIndex = carousel.current.flkty.dragEndRestingSelect();
      carousel.current.flkty.updateSelectedSlide();
      carousel.current.flkty.settle(carousel.current.flkty.x);
      window.requestAnimationFrame(update);
    }
  };

  const pause = () => {
    dispatch(app.toggleServiceScroller(false));
    window.cancelAnimationFrame(window.requestAnimationFrame(update));
  };

  const play = () => {
    if (!carouselIsScrolling) {
      dispatch(app.toggleServiceScroller(true));
      window.requestAnimationFrame(update);
    }
  };

  useEffect(() => {
    carousel.current.flkty.on("dragStart", () => {
      dispatch(app.toggleServiceScroller(false));
    });
    dispatch(app.toggleServiceScroller(false));
    update();
  }, []);

Solution

  • The reason is that I was changing carouselIsScrolling with state, that was waiting for the re render to use, but the re render was causing it to reset to initial value.

    I changed to using

    const carouselIsScrolling = useRef(true);
    

    and

     if (!carouselIsScrolling.current) return;
    

    and now it works.