react-native-pager-view
react-native-pager-view copied to clipboard
[@next] `useNativeDriver: true` in `onPageScroll` works with `PagerView`, but not `LazyPagerView`
Description
When using Animated.event in onPageScroll of LazyPagerView and setting useNativeDriver to true, the animated values of position and offset do not get updated at all.
The same setup works as intended with the regular PagerView.
This leads to poor performance of animations based on the page position.
Reproducible Demo
Here's a code snippet which uses PagerView and where the animated values are properly updated:
import React, {useRef} from 'react';
import {Animated, SafeAreaView, StyleSheet, Text, View} from 'react-native';
import {PagerView} from 'react-native-pager-view';
const AnimatedPagerView = Animated.createAnimatedComponent(PagerView);
const App = () => {
const position = useRef(new Animated.Value(0)).current;
const offset = useRef(new Animated.Value(0)).current;
const translateX = Animated.multiply(Animated.add(position, offset), 100);
return (
<SafeAreaView style={styles.container}>
<Animated.View style={[styles.block, {transform: [{translateX}]}]} />
<AnimatedPagerView
style={styles.container}
initialPage={0}
onPageScroll={Animated.event([{nativeEvent: {position, offset}}], {
useNativeDriver: true,
})}>
<View key="1" style={styles.page}>
<Text>1</Text>
</View>
<View key="2" style={styles.page}>
<Text>2</Text>
</View>
<View key="3" style={styles.page}>
<Text>3</Text>
</View>
</AnimatedPagerView>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {flex: 1},
block: {marginBottom: 20, width: 30, height: 30, backgroundColor: '#000'},
page: {borderWidth: 1},
});
export default App;
Here's the same setup which uses LazyPagerView and where the animated values are always at 0:
import React, {useRef} from 'react';
import {Animated, SafeAreaView, StyleSheet, Text, View} from 'react-native';
import {LazyPagerView} from 'react-native-pager-view';
const AnimatedLazyPagerView = Animated.createAnimatedComponent(LazyPagerView);
const App = () => {
const position = useRef(new Animated.Value(0)).current;
const offset = useRef(new Animated.Value(0)).current;
const translateX = Animated.multiply(Animated.add(position, offset), 100);
const data = [1, 2, 3];
const renderItem = ({item}) => (
<View key={item} style={styles.page}>
<Text>{item}</Text>
</View>
);
const extractKey = item => item + '';
return (
<SafeAreaView style={styles.container}>
<Animated.View style={[styles.block, {transform: [{translateX}]}]} />
<AnimatedLazyPagerView
style={styles.container}
initialPage={0}
onPageScroll={Animated.event([{nativeEvent: {position, offset}}], {
useNativeDriver: true,
})}
data={data}
renderItem={renderItem}
keyExtractor={extractKey}
/>
</SafeAreaView>
);
};
const styles = StyleSheet.create({
container: {flex: 1},
block: {marginBottom: 20, width: 30, height: 30, backgroundColor: '#000'},
page: {borderWidth: 1},
});
export default App;
Changing useNativeDriver: true to useNativeDriver: false restores the functionality, but degrades performance.
I've noticed that removing the wrapper around LazyPagerViewImpl and exporting LazyPagerViewImpl instead restores the useNativeDriver functionality.
https://github.com/callstack/react-native-pager-view/blob/next/src/LazyPagerView.tsx#L33
Is there any reason this wrapper was added? I could make a PR removing it.
Is there any reason this wrapper was added? I could make a PR removing it.
@alpha0010 Could you help me with above question ?
The wrapper dramatically reduced calls to the main render() function, which (depending on data, config, etc.) is heavy. If you do remove the wrapper, I recommend caching the renderChildren() call (for example, with memoize-one).
@alpha0010 then I believe declaring LazyPagerViewImpl as PureComponent should have the same effect without the need for a wrapper or manual memoization. Or is there something I'm missing?
Unfortunately, it has been too long since I worked on this for me to recall if I: did not test that, tested but it did not work, or maybe just implemented it wrong while testing (or maybe something else).
https://github.com/callstack/react-native-pager-view/issues/673