Search code examples
reactjstouchreact-hooks

React hooks scroll event performance issue


Task:

On touch devices get .container.scrollLeft and transform: translateX image depending on current horizontal scroll position. .container width bigger than its .wrapper.

Here you can check live example.

Problem:

Image moves but with an extremely low fps.

Expected behavior:

Fast and smooth movement.

Detailed description:

Thank you very much for reading this! I really get stacked with this issue. On desktop version, I'm just binding images position with onMouseMove events and everything is great. But with mobile version I tried onTouch events and native scroll event but nothing work as expected. I was looking for a solution or some working example and found nothing. So, here I am.


Solution

  • In this useEffect you're adding the scroll event listener on every render. So as it scrolls, it re-renders (as it should), but it re-adds the listener many times.

    useEffect(() => {
        handleScroll();
        wrapperEl.current.addEventListener("scroll", handleScroll, {
          passive: true
        });
      });
    

    It's far more efficient (and less likely to cause lumpy scrolling) to add the listener once on first render (using [] as the dependency array). You should also clean it up by returning a function that removes it on dismount:

    useEffect(() => {
        const el = wrapperEl.current;
        el.addEventListener("scroll", handleScroll, {
          passive: true
        });
        return () => el.removeEventListener("scroll", handleScroll);
      }, []);
    

    This is probably enough to get things running smoothly. If not, then you can also throttle your handleScroll calls - there are many hooks-based examples available.