react-native-pager-view: [Discussion] setPage should not trigger onPageSelected event
Bug
We are storing and updating the active index of the ViewPager in Redux. When the user swipes to another page the onPageSelected
event is correctly triggered and the active index will be updated like that:
<ViewPager
ref={pager}
pageMargin={0}
onPageSelected={({ nativeEvent }) => setActiveIndex(nativeEvent.position)}
style={[styles.pager, { width }]}
initialPage={0}
>
But we also want to set the page programatically when the active index is changed by some other component. To achieve this we are using an useEffect hook like this:
useEffect(() => {
pager.current && pager.current.setPageWithoutAnimation(activeIndex);
}, [activeIndex]);
Unfortunately calling setPageWithoutAnimation
triggers another onPageSelected
event which updates the active index which triggers the useEffect
hook and so on.
We think that there should be no onPageSelected
event triggered when setting the page programatically.
Environment info
React native info output:
System:
OS: macOS Mojave 10.14.6
CPU: (4) x64 Intel(R) Core(TM) i5-7360U CPU @ 2.30GHz
Memory: 5.96 GB / 16.00 GB
Shell: 3.2.57 - /bin/bash
Binaries:
Node: 10.16.3 - ~/.nvm/versions/node/v10.16.3/bin/node
Yarn: 1.19.1 - /usr/local/bin/yarn
npm: 6.13.1 - ~/.nvm/versions/node/v10.16.3/bin/npm
Watchman: 4.9.0 - /usr/local/bin/watchman
SDKs:
iOS SDK:
Platforms: iOS 13.2, DriverKit 19.0, macOS 10.15, tvOS 13.2, watchOS 6.1
Android SDK:
API Levels: 21, 22, 23, 24, 25, 26, 27, 28
Build Tools: 23.0.1, 25.0.2, 25.0.3, 26.0.1, 26.0.2, 26.0.3, 27.0.3, 28.0.1, 28.0.3, 29.0.2
System Images: android-19 | Google APIs Intel x86 Atom, android-21 | Google APIs Intel x86 Atom_64, android-22 | Intel x86 Atom_64, android-22 | Google APIs Intel x86 Atom_64, android-23 | Google APIs Intel x86 Atom_64, android-26 | Intel x86 Atom_64, android-27 | Google APIs Intel x86 Atom, android-28 | Google APIs Intel x86 Atom
Android NDK: 20.1.5948944
IDEs:
Android Studio: 3.5 AI-191.8026.42.35.6010548
Xcode: 11.3/11C29 - /usr/bin/xcodebuild
npmPackages:
react: 16.9.0 => 16.9.0
react-native: 0.61.5 => 0.61.5
Library version: 3.3.0
About this issue
- Original URL
- State: open
- Created 5 years ago
- Reactions: 11
- Comments: 25 (5 by maintainers)
Ideally would be good to have react-native-viewpager as controlled component. Instead of
initialPage
might be better to havepage
which will control selected page.@crystalneth not yet. what you describe is exactly our problem. I’ll take a closer look this week and let you know.
I have the same issue. Distinguishing between desiredIndex and currentIndex isn’t really possible, because we can’t distinguish between a user initiated page scroll and programmatically initiated one, at least without some transitioning state variable.
You can see in the code below, if a user taps to change the segmented control index from 0 to 1, then back to 0 before the pager has finished transitioning to 1, then the onPageSelected event will fire with ‘1’ before the user initiated transition back to 0 has started. An infinite loop ensues.
Note that unlike the above example I am using animations, which I do want.
Also note that the SegmentedControlIOS onChange event does not fire when its index is programmatically changed, however the ViewPager event does fire when its index is programmatically change. I believe the former is the correct behavior.
What do you think about using a
desiredIndex
value as the useEffect dependency, so you have no infinite loop?To be clear, I disagree with removing the onPageSelected event, because in this example, “current” and “desired” page values are not properly separated.