Infinite scrolling is one of the most common ways mobile apps display a large amount of content to users. The ability to continue scrolling while new data is automatically fetched for you has seen a lot of success over the years, even if it’s not ideal for all scenarios.
While implementing an infinitely scrolling list, most of the focus tends to be on what happens as the user scrolls down the page. But what about what happens when they want to scroll back up? Scrolling back to the top of an infinitely scrolling list is often overlooked.
There are often tappable elements on the screen such as the navigation bar or the active tab that will scroll the user back to the top of the list. But what does it look like to implement this behavior in scratch with React Native? Let’s find out!
Step 1. Creating the Button
The first step of creating a button that scrolls to the top of the list is to create the actual button. Any type of button will work, but you will most likely need to place it on top of the content in the list. A Floating Action Button (FAB) is perfect for this. Component libraries such as React Native Paper have one readily available if you want to use it.
All we need is a tappable component that is absolutely positioned over the infinitely scrolling list. In this example, I’m using the Icon component from React Native Elements.
const ListView = () => {
return (
<View>
// infinitely scrolling list setup goes here
<Icon
name="north"
type="material"
color='teal'
raised
reverse
containerStyle={styles.scrollTopButton}
/>
</View>
);
};
const styles = StyleSheet.create({
scrollTopButton: {
position: 'absolute',
bottom: 0,
right: 0
},
};
Step 2. Implementing “Scroll to Top”
Now that we have the button in place, it’s time to make it functional. Infinitely scrolling lists in React Native are often implemented using the FlatList component. That’s because they’re more performant than the ScrollView component for large sets of data. Conveniently, FlatList
has a scrollToOffest method that we can use to achieve the “scroll to top” behavior that we’re looking for. But how do we access this method?
Accessing the current FlatList
component can be done using the useRef React Hook. This hook allows us to configure a new reference and bind it to the FlatList
using its ref
property. From there, we can access that reference when our button is pressed and use it to call the scrollToOffset
method.
const ListView = () => {
const listRef = useRef(null);
return (
<View>
// simplified FlatList configuration as an example
<FlatList ref={listRef}/>
<Icon
// previously configured Icon props
containerStyle={styles.scrollTopButton}
onPress={() => {
listRef.current.scrollToOffset({ offset: 0, animated: true });
}
/>
</View>
);
};
const styles = StyleSheet.create({
scrollTopButton: {
position: 'absolute',
bottom: 0,
right: 0
},
};
Step 3. Conditionally Displaying the Button
We now have a working “scroll to top” button, but it’s always displayed even when the user is already at the top of the list. If this isn’t an issue for you, feel free to skip this step. In order to hide the button while the user is at the top of the list, we will need to determine the vertical offset of the content in the list. Luckily there is an option on the FlatList
that we can utilize for this: the onScroll
property.
The onScroll
event fires, at most, once per frame as the user scrolls, calling a function with the event as a parameter. This event has a contentOffset
field that we can use for our needs. Using this contentOffset
and the useState
React Hook, we can determine how far down the user has scrolled. That way, we can conditionally show/hide the “scroll to top” button.
const ListView = () => {
const listRef = useRef(null);
const [contentVerticalOffset, setContentVerticalOffset] = useState(0);
const CONTENT_OFFSET_THRESHOLD = 300;
return (
<View>
// simplified FlatList configuration as an example
<FlatList
ref={listRef}
onScroll={event => {
setContentVerticalOffset(event.nativeEvent.contentOffset.y);
}}
/>
{contentVerticalOffset > CONTENT_OFFSET_THRESHOLD && (
<Icon
// previously configured Icon props
containerStyle={styles.scrollTopButton}
onPress={() => {
listRef.current.scrollToOffset({ offset: 0, animated: true });
}}
/>
)}
</View>
);
};
const styles = StyleSheet.create({
scrollTopButton: {
position: 'absolute',
bottom: 0,
right: 0
},
};
As the user scrolls down the list and passes the configured threshold, the button will appear. And as they scroll back up, it will disappear. Perfect!
Here is my example React Native project (without infinite scrolling, to be fair). It shows how all of this fits together in an actual project. I hope you’ll find this helpful.
Very simple, concise, and functional.
Much appreciated :)