necolas/react-native-web

ScrollView: momentum scroll events

necolas opened this issue · 8 comments

Look into supporting momentum scroll events.

I guess that to add support for the scroll momentum callbacks there needs to be a way to detect if the scroll is done with momentum.

You could always check for the scroll speed, but that is not really the same thing as you call do a scroll movement fast without it having momentum.

Is anyone aware of any existing Javascript implementations where such gesture would be detected?

My initial thought is that if a scroll is initiated by a touch, and scroll events are still firing while there is no active touch, we're in a "momentum" phase of the scroll. I don't think momentum events can exist for mouse/wheel-triggered scrolls. And the drag start event would fire when touch-scrolling starts, and drag end would fire when touch-scrolling ends. But would have to check when the events fire for native to confirm.

MoOx commented

I don't think momentum events can exist for mouse/wheel-triggered scrolls

At least on macos with a trackpad you can experience them in all browsers.


Might this help to finish touchable support as some issues with those might be related to some missing events (eg: for scroll responder?)

me too

For anyone needing a temp workaround I made a hook...

// hooks.js

export const useWebOnScroll = ({ onScroll, onScrollEnd }) => {
  const lastScrollEvent = useRef(null);
  const scrollEndTimeout = useRef(null);

  const handleWebScroll = event => {
    onScroll(event);

    const timestamp = Date.now();

    if (scrollEndTimeout.current) {
      clearTimeout(scrollEndTimeout.current);
    }

    if (lastScrollEvent.current) {
      // Scroll ended
      scrollEndTimeout.current = setTimeout(() => {
        if (lastScrollEvent.current === timestamp) {
          lastScrollEvent.current = null;
          onScrollEnd && onScrollEnd(event);
        }
      }, 500);
    }

    lastScrollEvent.current = timestamp;
  };

  useEffect(() => {
    return () => {
      scrollEndTimeout.current && clearTimeout(scrollEndTimeout.current);
    };
  }, []);

  return handleWebScroll;
};

// Component.js


const Component = ({onScroll, onScrollEnd}) => {
    const handleWebScroll = useWebOnScroll({ onScroll, onScrollEnd })

    <ScrollView onScroll={Platform.select({ web: handleWebScroll, default: onScroll })} />
}

Anyone know if this has been fixed or if there's another way of achieving this effect on RN web?

Here's my solution: #2249 (comment)