react-native icon indicating copy to clipboard operation
react-native copied to clipboard

(Android/FlatList) Fix onMomentumScrollEnd being called multiple times

Open huangkaiyuan opened this issue 3 years ago • 26 comments

Description

image

Version

0.64.1

Output of react-native info

image

Steps to reproduce

image

Snack, code example, screenshot, or link to a repository

No response

huangkaiyuan avatar Dec 02 '21 10:12 huangkaiyuan

Observing the same symptom. FYI, the onMomentumScrollBegin was triggered only once, but the onMomentumScrollEnd was trigged around 3~5 times.

image

fanyangxi avatar Dec 09 '21 09:12 fanyangxi

Same bug occurs on the ScrollView component

Arjan-Zuidema avatar Dec 15 '21 14:12 Arjan-Zuidema

+1

meowcorp avatar Dec 31 '21 17:12 meowcorp

Was able to reproduce it on the 0.66.4 version. Android only. Hermes is enabled (maybe it would be useful). I have faced with that issue on 0.64.2 first time. But it's still reproducible.

anton-patrushev avatar Jan 05 '22 22:01 anton-patrushev

+1

rubydeve avatar Jan 13 '22 09:01 rubydeve

This is how it worked for me

const [canmomentum, setCanMomentum] = useState(false);
<ScrollView
      onScroll={( event ) => {
           setCanMomentum(true)
     }}
     onMomentumScrollEnd={() => {
           if (canmomentum) console.log('onMomentumScrollEnd')
           setCanMomentum(false)
     }}
>
     <Content/>
</ScrollView>

rubydeve avatar Jan 13 '22 10:01 rubydeve

This is how it worked for me

const [canmomentum, setCanMomentum] = useState(false);
<ScrollView
      onScroll={( event ) => {
           setCanMomentum(true)
     }}
     onMomentumScrollEnd={() => {
           if (canmomentum) console.log('onMomentumScrollEnd')
           setCanMomentum(false)
     }}
>
     <Content/>
</ScrollView>

Thanks for this suggestion, I did something similar but with a ref instead to avoid unnecessary state updates and renders.

ewnavilae avatar Feb 22 '22 13:02 ewnavilae

This is how it worked for me

const [canmomentum, setCanMomentum] = useState(false);
<ScrollView
      onScroll={( event ) => {
           setCanMomentum(true)
     }}
     onMomentumScrollEnd={() => {
           if (canmomentum) console.log('onMomentumScrollEnd')
           setCanMomentum(false)
     }}
>
     <Content/>
</ScrollView>

Thanks for this suggestion, I did something similar but with a ref instead to avoid unnecessary state updates and renders.

I didn't find how to reference the scrolling state from ref. would you agree to share your solution?

achiyazigi avatar Mar 14 '22 12:03 achiyazigi

This is how it worked for me

const [canmomentum, setCanMomentum] = useState(false);
<ScrollView
      onScroll={( event ) => {
           setCanMomentum(true)
     }}
     onMomentumScrollEnd={() => {
           if (canmomentum) console.log('onMomentumScrollEnd')
           setCanMomentum(false)
     }}
>
     <Content/>
</ScrollView>

Thanks for this suggestion, I did something similar but with a ref instead to avoid unnecessary state updates and renders.

I didn't find how to reference the scrolling state from ref. would you agree to share your solution?

Second this, please share thy precious knowledge of the hooks. Saveth me from mine own perils! @ewnavilae I beg of you.

asr1191 avatar Apr 05 '22 22:04 asr1191

Solution using useRef:

const canMomentum = React.useRef(false);

const onMomentumScrollBegin = () => {
  canMomentum.current = true;
};

const onMomentumScrollEnd = () => {
  if (canMomentum.current) {
    // console.log('onMomentumScrollEnd');
  }

  canMomentum.current = false;
};

return (
  <ScrollView
    onMomentumScrollBegin={onMomentumScrollBegin}
    onMomentumScrollEnd={onMomentumScrollEnd}
  ></ScrollView>
);

josecarlosrx avatar Apr 20 '22 17:04 josecarlosrx

I'm having the same issue in version 0.68.2

MarceloNascc avatar Sep 18 '22 19:09 MarceloNascc

Still an issue in version 0.69.6

RobbertMerapar avatar Dec 21 '22 14:12 RobbertMerapar

Still an issue in version 0.70

MichHighlander avatar Jan 16 '23 12:01 MichHighlander

Any update on this? The workaround doesn't work if using the snapToInterval because its the last event that is correct. I can put in a debounce but it is way too long of a debounce since the onMomentumScrollEnd gets called almost a second apart.

When using snapToInterval, and user drags very little and lets go, it snaps back to the original snap location, but onMomentumScrollEnd gets called twice. once for the temp scrolled location and once for the new location

stingerdallas avatar Mar 18 '23 17:03 stingerdallas

Still an issue in version 0.71.7

kirx76 avatar Apr 26 '23 06:04 kirx76

+1

wyeo avatar May 15 '23 08:05 wyeo

+1

Jlexyc avatar Jun 11 '23 23:06 Jlexyc

+1

Bowlerr avatar Jun 26 '23 23:06 Bowlerr

Looks like this will be fixed by https://github.com/facebook/react-native/pull/32433.

gaearon avatar Oct 04 '23 03:10 gaearon

Note there's a similar problem for onScrollBeginDrag (which gets called twice). I don't know if that PR fixes it.

gaearon avatar Oct 04 '23 03:10 gaearon

I'm still having this issue in react-native 0.72.6.

clicktodev avatar Nov 08 '23 14:11 clicktodev

Solution using useRef:

const canMomentum = React.useRef(false);

const onMomentumScrollBegin = () => {
  canMomentum.current = true;
};

const onMomentumScrollEnd = () => {
  if (canMomentum.current) {
    // console.log('onMomentumScrollEnd');
  }

  canMomentum.current = false;
};

return (
  <ScrollView
    onMomentumScrollBegin={onMomentumScrollBegin}
    onMomentumScrollEnd={onMomentumScrollEnd}
  ></ScrollView>
);

This works but the event is called too early, it doesn't wait for the animation to end.

clicktodev avatar Nov 18 '23 07:11 clicktodev

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

github-actions[bot] avatar May 17 '24 05:05 github-actions[bot]

It must be fixed in RN 0.74.1 https://github.com/facebook/react-native/commit/06668fcbacd750771f1d53cce829dc55e86f3f3c

xaiamov avatar May 22 '24 10:05 xaiamov

Not fixed :(

Iuriy-Budnikov avatar Jun 04 '24 10:06 Iuriy-Budnikov

Using RN 0.74.3 and can confirm that this issue has been fixed.

mars-lan avatar Jul 04 '24 22:07 mars-lan

This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days.

react-native-bot avatar Jan 01 '25 05:01 react-native-bot

looks like this is fixed, should probably be closed.

tested on expo 52 https://snack.expo.dev/@hichem_fantar/onmomentumscrollend-example

clicktodev avatar Jan 01 '25 16:01 clicktodev

actually it seems the behavior isn't consistent between android and ios. on android it works when you flick and release, it also works when you scroll and hold thereby controlling the scrolling.

on IOS it only works when you flick and let the scroll momentum end by itself.

Android:

https://github.com/user-attachments/assets/706f34b0-c19c-49c2-887c-d035d2119fee

iOS:

https://github.com/user-attachments/assets/9a0cafe0-7370-4359-bd63-4dcc16cb9a51

clicktodev avatar Jan 01 '25 16:01 clicktodev

I created a separate issue here: https://github.com/facebook/react-native/issues/48423 i believe this can be closed now since it's a different issue

clicktodev avatar Jan 01 '25 17:01 clicktodev