InfiniteScrollView
InfiniteScrollView is a React Native scroll view that notifies you as the scroll offset approaches the bottom. You can instruct it to display a loading indicator while you load more content. This is a common design in feeds. InfiniteScrollView also supports horizontal scroll views.
It conforms to ScrollableMixin so you can compose it with other scrollable components.
Installation
npm install --save react-native-infinite-scroll-view
Usage
Compose InfiniteScrollView with the scrollable component that you would like to get events from. In the case of a basic ListView, you would write:
;;; Component _loadMoreContentAsync = async { // Fetch more data here. // After fetching data, you should update your ListView data source // manually. // This function does not have a return value. } { return <ListView renderScrollComponent= <InfiniteScrollView ...props /> dataSource=... renderRow=... canLoadMore=thisstatecanLoadMoreContent onLoadMoreAsync=this_loadMoreContentAsync /> ; }
A more complete example that uses a ListView.DataSource
, react-redux, and supports pagination would look something like this:
;;;; Component static propTypes = // Assume data shape looks like: // {items: ["item1", "item2"], nextUrl: null, isFetching: false} listData: PropTypesobjectisRequired // dispatch is automatically provided by react-redux, and is used to // interact with the store. dispatch: PropTypesfuncisRequired ; { superprops context; thisstate = dataSource: rowHasChanged: this_rowHasChanged ; // Update the data store with initial data. thisstatedataSource = this; } async { // Initial fetch for data, assuming that listData is not yet populated. this; } { // Trigger a re-render when receiving new props (when redux has more data). this; } { // See the ListView.DataSource documentation for more information on // how to properly structure your data depending on your use case. let rows = propslistDataitems; let ids = rows; return thisstatedataSource; } { // You might want to use a different comparison mechanism for performance. return JSON !== JSON; } { // Reload all data return <RefreshControl refreshing=thispropslistDataisFetching onRefresh=this_loadMoreContentAsync /> ; } _loadMoreContentAsync = async { // In this example, we're assuming cursor-based pagination, where any // additional data can be accessed at this.props.listData.nextUrl. // // If nextUrl is set, that means there is more data. If nextUrl is unset, // then there is no existing data, and you should fetch from scratch. thisprops; } { return <ListView renderScrollComponent= <InfiniteScrollView ...props /> dataSource=thisstatedataSource renderRow=... refreshControl=this canLoadMore=!!thispropslistDatanextUrl onLoadMoreAsync=this_loadMoreContentAsync /> ; } const mapStateToProps = { return listData: statelistData;}; mapStateToPropsExampleComponent;
Tips and Caveats
- Horizontal scroll views are supported
- When you load more content in an infinite ListView, the ListView by default will render only one row per frame. This means that for a short amount of time after loading new content, the user could still be very close to the bottom of the scroll view and may trigger a second load.
- Known issue: Make sure your initial data reaches the bottom of the screen, otherwise scroll events won't trigger. Subsequent loads are not affected. See expo/react-native-infinite-scroll-view#9 for more details.
Implementation
InfiniteScrollView uses the onScroll
event to continuously calculate how far the scroll offset is from the bottom.