React Native: How To Build  Bidirectional Infinite Scroll
Tags: reactnative, infinitescroll, opensource
Published: 2021-03-01 15:50:13

---
title: React Native: How To Build  Bidirectional Infinite Scroll
published: true
description: Learn how to implement a smooth bidirectional infinite scroll in React Native
tags: reactnative, infinitescroll, opensource
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o1xdqp5k50ko78x0dodl.png
canonical_url: https://getstream.io/blog/react-native-how-to-build-bidirectional-infinite-scroll/
---

## 👋 Introduction
​
There have been many discussions on Stack Overflow and GitHub around implementing infinite scroll using React Native, on top of `FlatList` or `SectionList`. I've found that there aren't any easy solutions out there for bidirectional infinite scroll, which works on both Android and iOS. Recently, while working on `v3.0.0` of [React Native Chat SDK](https://github.com/GetStream/stream-chat-react-native) at [Stream](https://getstream.io/), we added bidirectional infinite scroll to our chat components. We had to jump through plenty of hurdles to make it happen while maintaining a good user experience around scrolling (especially for Android). Thus we decided to publish an excellent and small open-source package, on top of `FlatList`, to make this task easier for other React Native developers.​

**GitHub ⭐ :** [github.com/getstream/react-native-bidirectional-infinite-scroll](https://github.com/GetStream/react-native-bidirectional-infinite-scroll)

​
### 🔌 Usage

As mentioned earlier, this package is a wrapper around FlatList, and so it can be used exactly like FlatList from React Native, with few additional props:

![Usage](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/euj48dje72sea9ps3nn3.png)

​
### 🔮 Quick Preview

> _Scroll down further, for the [tutorial](#🖥-tutorial-chat-ui-with-bidirectional-infinite-scroll)_

| iOS | Android |
| ------------------------------------------------------------------------------------------------------------------------------- | :-----------------------------------------------------------------------------------------------------------------------------: |
| ![Alt Text](https://stream-blog-v2.imgix.net/blog/wp-content/uploads/c0771f9436c1c694f15b6aa3b4115c99/dvg7qhro5044qfvqn3v8.gif) | ![Alt Text](https://stream-blog-v2.imgix.net/blog/wp-content/uploads/5474d3098fc7fef405dd55b4da36c9a9/tae5gh1l0aopprx4uyh4.gif) |
​
----


## Let's Dive Deep

  * [What and How?](#what-and-how)
  * [Tutorial: Chat UI With Bidirectional Infinite Scroll](#🖥-tutorial-chat-ui-with-bidirectional-infinite-scroll)
  * [What's more?!](#congratulations-whats-more)

​​​

## 📚 What and How

This section will walk you through the hurdles of implementing bidirectional infinite scroll and how we solved them.
​
### Support for `onStartReached`
[FlatList](https://reactnative.dev/docs/flatlist) from React Native has built-in support for infinite scroll in a single direction (from the end of the list). You can add a prop `onEndReached`on `FlatList`. This function gets called when your scroll is near the end of the list, and thus you can append more items to the list from this function. You can Google for **React Native infinite scrolling**, and you will find plenty of examples for this. Unfortunately, the `FlatList` doesn't provide any similar prop for `onStartReached` for infinite scrolling in other directions.
​
We have added support for this prop as part of this package by simply adding the `onScroll` handler on `FlatList`, and executing the callback function (`onStartReached`) when the scroll is near the start of the list. If you take a look at the implementation of [VirtualizedList](https://github.com/facebook/react-native/blob/master/Libraries/Lists/VirtualizedList.js), you will notice that `onEndReached`function gets called only once per content length. That's there for a good purpose - to avoid redundant function calls on every scroll position change. Similar optimizations have been done for `onStartReached` within this package.
​
### Race condition between `onStartReached` and `onEndReached`

To maintain a smooth scrolling experience, we need to manage the execution order of `onStartReached` and `onEndReached`. Because if both the callbacks happen at (almost) the same time, which means items will be added to the list from both directions. This may result in scroll jump, and that's not a good user experience. Thus it's essential to make sure one callback waits for the other callback to finish.
​
### `onStartReachedThreshold` and `onEndReachedThreshold`

`FlatList` from React Native has a support for the prop `onEndReachedThreshold`, which is [documented here](https://reactnative.dev/docs/flatlist#onendreachedthreshold)
​
> How far from the end (in units of visible length of the list) the bottom edge of the list must be from the end of the content to trigger the `onEndReached` callback.


Instead, it's easier to have a fixed value offset (distance from the end of the list) to trigger one of these callbacks. Thus we can maintain these two values within our implementation. So `onStartReachedThreshold` and `onEndReachedThreshold` props accept the number - distance from the end of the list to trigger one of these callbacks.
​
### Smooth scrolling experience
`FlatList` from React Native accepts a prop - [maintainVisibleContentPosition](https://reactnative.dev/docs/scrollview#maintainvisiblecontentposition), which makes sure your scroll doesn't jump to the end of the list when more items are added to the list. But this prop is only supported on iOS for now. So taking some inspiration from this [PR](https://github.com/facebook/react-native/pull/29466), we published our separate package to add support for this prop on Android - [flat-list-mvcp](https://github.com/GetStream/flat-list-mvcp#maintainvisiblecontentposition-prop-support-for-android-react-native). And thus `@stream-io/flat-list-mvcp` is a dependency of the `react-native-bidirectional-scroll` package.
​
## 🖥 Tutorial: Chat UI With Bidirectional Infinite Scroll

Now let's see how we can implement a chat message list, scrolling infinitely in both directions.

### Setup

Let's start by creating a React Native app:

```
$ npx react-native init AwesomeChatList
$ cd AwesomeChatList
```
​
Add the required dependencies:

```
$ yarn add react-native-bidirectional-infinite-scroll @stream-io/flat-list-mvcp
```

Next, run the app:

```
$ npx react-native run-ios
```

> Note: The server will auto-refresh as you make changes to the code.

​
### Create message list

Open this project in some editor (I love VS Code) and open `App.js` in the project's root directory.
​
We are going to populate the list with dummy messages. In a real application, these messages are queried against a server. For example, we can write a simple utility function to mock this API call for querying `n` number of messages.
​
Create a file - `utils.js`

{% gist https://gist.github.com/vishalnarkhede/0cfaf5b31c00429d4bb203014975f31f %}

Next, let's write a small UI component for the message bubble. Create a file named `MessageBubble.js`.​
{% gist https://gist.github.com/vishalnarkhede/22394f80d629daea1f438ddf42a10ba0 %}​
Now let's first implement a simple list, which renders these messages on the first load. Copy the following content to `App.js` and hit save.

{% gist https://gist.github.com/vishalnarkhede/3f822f7aa329d757b64e20ee256cbdcf %}

You should be able to see the list of messages as shown in the screenshot on the right.
​
![Message List](https://stream-blog-v2.imgix.net/blog/wp-content/uploads/546da9ee13625ce4f5ebba16747e50a0/0coucxr19ywzwftsicgq.png)

### Add Infinite Scroll

Next, let's implement infinite scroll to the list by adding `onStartReached` and `onEndReached` prop functions.

- `onStartReached` - add 10 messages at the beginning of the list
- `onEndReached` - add 10 messages at the end of the list
​

Replace the contents of `App.js` with the following:
​
{% gist https://gist.github.com/vishalnarkhede/70fe2a544fbf3db74fdc6bbfe95efc6e %}

And that's it. If you scroll up or down, you will see new messages being loaded in the list and scroll position being maintained as well (both for Android and iOS)
​
![Bidirectional Infinite Scroll](https://stream-blog-v2.imgix.net/blog/wp-content/uploads/c6394ba8863774747d8bb552e28200ad/dvg7qhro5044qfvqn3v8.gif)
​
### Send Message

In real chat applications, you don't actually "infinitely" scroll. There is always an end to the `loadMoreRecentMessages` function. And after this point, you will want the scroll to automatically move to the bottom of the list, as other users send a new message or if you send a new message.
​
Basically, after this point, we want to enable the "autoscroll to top" (bottom in our case, since the list is inverted) functionality of `FlatList`. You can do this by setting a prop `enableAutoscrollToTop` as `true`. Additionally, you can also set `autoscrollToTopThreshold` to `true`.
​
- Let's try to simulate this scenario by keeping a counter on the number of times recent messages were queried. Once the counter crosses 2, let's stop querying the message.
​
- Let's add a "Send Message" button at the bottom to send a single message.
​

Replace the contents of `App.js` with following

{% gist https://gist.github.com/vishalnarkhede/5712c0922e12f927ad65053f9ce3fe25 %}

Now scroll to the bottom couple of times, until you can't load any more recent messages. Now try to send a single message by pressing the "Send Message" button. You will see scroll automatically scrolling to the bottom of the list. But if you scroll up a bit and then send a message - then the scroll position will be maintained. The `autoscrollToTopThreshold` prop controls this threshold.

![Send Message](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3wdzvxpcdabfeuv98nvn.gif)
​
## 🎉 Congratulations!! Whats more?!

You've implemented a bidirectional infinite scroll with React Native! Additionally following props are available to add more customisations:

- `activityIndicatorColor`
- `enableAutoscrollToTop`
- `autoscrollToTopThreshold`
- `onStartReachedThreshold`
- `onEndReachedThreshold`
- `showDefaultLoadingIndicators`
- `HeaderLoadingIndicator`
- `FooterLoadingIndicator`

I hope you found it useful. Feel free to add some questions, comments, and feedback here. And don't forget to put a ⭐ on [github repo](https://github.com/GetStream/react-native-bidirectional-infinite-scroll). Happy Coding!!