Description
Calling scrollToIndex on flashlist when flashlist is out of focus doesn't seem to work.
I have a page like this ;
const HomePage = () => {
const dispatch = useDispatch();
const route = useRoute()
const flashListRef = useRef(null);
const scrollPosition = useRef(0)
const navigation = useNavigation();
const [refreshing, setRefreshing] = useState(false);
const shouldRender = useNavigationState((state) => state.routes.length < 3 || state.routes.slice(-3).some(r => r.key === route.key));;
const {user} = useSelector((state) => state.auth);
const {images, isLoading, hasMore, refreshLoading} = useSelector((state) => state.images);
useEffect(() => {
dispatch(fetchImages({lastImageId: null, isAppending: false}));
}, []);
const handleScroll = (event) => {
scrollPosition.current = event.nativeEvent.contentOffset.y; // Get current offset
};
const renderItem = useCallback(
({item}) => <TestComponent item={item}/>
[]
);
useEffect(() => {
if(shouldRender){
if (flashListRef.current && scrollPosition.current !== 0) {
try {
flashListRef.current.scrollToOffset({
offset: scrollPosition.current, // Use the saved offset
animated: false, // You can set this to true if you want an animated scroll
});
} catch (e) {
console.error(e)
}
}
}
}, [shouldRender]);
if (!shouldRender) {
return null;
}
return (
<View style={styles.container}>
<FlashList
ref={flashListRef}
data={images}
keyExtractor={item => item.id.toString()}
onScroll={handleScroll}
scrollEventThrottle={16}
renderItem={renderItem}
/>
)}
</View>
);
};
The idea behind this component is that we keep track of the users scrolling on the page and when they leave we save it. As my app supports almost infinite navigation, similar to how a social media app may allow you to navigate from profile to profile, I need a way to optimise the page rendering so I don't render every page and run out of memory. My workaround for this is to only ever render the previous previous three pages and each page listens to the navigation state to see if its in the last three pages. If it is the component renders so that it is ready for the user, if not it returns null, conserving memory. This is what the shouldRender
variable does here.
This works with flatlist, however, when doing this with flashlist the page always re-renders with the scroll position at zero, even though the scrollToIndex does execute.
Refactoring my code to only scroll when the page is in focus, works.
const HomePage = () => {
const dispatch = useDispatch();
const route = useRoute()
const flashListRef = useRef(null);
const scrollPosition = useRef(0)
const navigation = useNavigation();
const [refreshing, setRefreshing] = useState(false);
const {user} = useSelector((state) => state.auth);
const {images, isLoading, hasMore, refreshLoading} = useSelector((state) => state.images);
useEffect(() => {
dispatch(fetchImages({lastImageId: null, isAppending: false}));
}, []);
const handleScroll = (event) => {
scrollPosition.current = event.nativeEvent.contentOffset.y; // Get current offset
};
const renderItem = useCallback(
({item}) => <TestComponent item={item}/>
[]
);
const isFocused = useIsFocused();
useEffect(() => {
if(isFocused){
if (flashListRef.current && scrollPosition.current !== 0) {
try {
flashListRef.current.scrollToOffset({
offset: scrollPosition.current, // Use the saved offset
animated: false, // You can set this to true if you want an animated scroll
});
} catch (e) {
console.error(e)
}
}
}
}, [isFocused]);
if (!isFocused) {
return null;
}
return (
<View style={styles.container}>
<FlashList
ref={flashListRef}
data={images}
keyExtractor={item => item.id.toString()}
onScroll={handleScroll}
scrollEventThrottle={16}
renderItem={renderItem}
/>
)}
</View>
);
};
However, my concern here is that the scroll won't happen on time on all devices so the user will see the page jump. This seems like a bug to me but maybe it is intentional.
Current behavior
Calling scrollToIndex when page is out of focus does not work
Expected behavior
Calling scrollToIndex when page is out of focus should work
To Reproduce
See Sample code above
Platform:
- iOS
- Android
Environment
1.7.1