📜 ⬆️ ⬇️

Infinite scrolling on Firebase

In this article, you will learn how to implement endless scrolling using JavaScript and Firebase, while you will not need to change anything in your existing data structure for Firebase.

I tried to write this article in such a way that the information in it was as universal and practical as possible for any framework / library, so I hope that every step that is necessary to implement the ideas in your projects will be as clear as possible.

Note: if the trial information does not interest you, feel free to skip to the code examples below.
')


Introduction


Before we begin, let's define the expected behavior:


In addition, we need to define test data for which we will try to implement a sample from Firebase: using this approach, it will be easier for me to give you a vivid example of what is happening with requests.

//    Firebase items: { firstInsertedItem: { … }, // oldest SecondInsertedItem: { … }, ThirdInsertedItem: { … }, FourthInsertedItem: { … }, FifthInsertedItem: { … }, SixthInsertedItem: { … }, SeventhInsertedItem: { … }, EighthInsertedItem: { … }, NinethInsertedItem: { … }, TenthInsertedItem: { … }, // newest } //        

Push keys for Firebase


We start with the fact that I will reveal to you all the beauty of push keys for Firebase, and also tell you about how with their help we implement our idea.

Firebase push keys are not just a collection of random characters. It turns out that the push keys firebase consist of a combination of timestamps and random data encoded in the modified base64 alphabet to preserve their chronological order (that is, the order in which they are inserted).

This indispensable feature will allow us to sort Firebase requests.

Now go to the direct development.

First step


In order for all our samples, following the very first sample, to return exactly the data they need to return, we will need to create some reference for the key that was chosen before everyone else.

Let's define a variable as follows:

 let referenceToOldestKey = ''; 

Original sample


The next step is to create a query for a selection of the first 5 nested items:

 firebase.database().ref('items') .orderByKey() .limitToLast(5) .once('value') .then((snapshot) => { … } ) .catch((error) => { … } ); 

This query performs the following actions:


The result will look like this:

 { SixthItemFromTheEnd: { … }, SeventhItemFromTheEnd: { … }, EighthInsertedItem: { … }, NinethInsertedItem: { … }, TenthInsertedItem: { … }, } 

Then we need to change the order of the elements for the result: the last element should have been on top, not below.

There are several options for this purpose, depending on how you will manage the state of your application:


We will choose the second option, since it is the most common method for storing this kind of data.

Add the following piece of code in .then for our fetch function:

 let arrayOfkeys = Object.keys(snapshot.val()); let results = arrayOfkeys .map(key => snapshot.val()[key]) .reverse(); 

Next, we need to initialize our link, starting with the most recent of the 5 keys, so that when the user scrolls down the page, our next sample function will recognize the element required for scrolling.

 referenceToOldestKey = arrayOfkeys[0]; 

(The most recent key is in position [0], because limitToLast returns the elements in chronological order.)

So, we are done with the first sample.

Next sample


Now let's make it so that when the user scrolls to the end of the page, the selection for the first 5 elements is activated. For this we will write the following query:

 firebase.database().ref('items') .orderByKey() .endAt(referenceToOldestKey) .limitToLast(6) .once('value') .then((snapshot) => { … } ) .catch((error) => { … } ); 

This query does the following:


The result will be as follows:

 { firstInsertedItem: { … }, SecondInsertedItem: { … }, ThirdInsertedItem: { … }, FourthInsertedItem: { … }, FifthInsertedItem: { … }, SixthInsertedItem: { … }, } 


Since the endAt method is inclusive, i.e. our source key is included in the returned object (or in the result). Thus, if we were limited to only 5 elements, then we would be able to use only 4 new elements: 1 would be a duplicate. You need to make a request for 6 items, and then delete the 6th item on the client side.

Now that we have figured out how the request works, we need to cancel the returned object and remove the duplicate.

 let arrayOfkeys = Object.keys(snapshot.val()); let results = arrayOfkeys .map(key => snapshot.val()[key]) .reverse() .slice(1); 

Why slice (1) ? After reverse (), our copy moves from the last position to the first. How to understand that the copy was in the last position? All keys are returned in chronological order.

Finally, for the link, we need to write the value of the last key from the current selection.

 referenceToOldestKey = arrayOfkeys[0]; 

Thus, everything necessary for the subsequent sampling is done.

This concludes my brief guide. Thanks to all who read for your attention, and I really hope that you have learned something new for yourself from my article. Below is the complete code example.

Full code example


Note: duplicating the code inside .then for both requests has been shown here for better code perception. So, to find the desired fragment, you do not need to study the entire code, as, for example, in the case of placing the code in a separate function.

 let referenceToOldestKey = ''; if (!referenceToOldestKey) { firebase.database().ref('items') .orderByKey() .limitToLast(5) .once('value') .then((snapshot) => { let arrayOfkeys = Object.keys(snapshot.val()); let results = arrayOfKeys .map(key => snapshot.val()[key]) .reverse(); //   referenceToOldestKey = arrayOfkeys[0]; //    ,  //    ({ … })   redux }) .catch((error) => { … } ); } else {  firebase.database().ref('items') .orderByKey() .endAt(oldestKeyReference) .limitToLast(6) .once('value') .then((snapshot) => { let arrayOfkeys = Object.keys(snapshot.val()); //    & //   //   & let results = arrayOfkeys .map(key => snapshot.val()[key]) .reverse() .slice(1); //   referenceToOldestKey = arrayOfkeys[0]; //    ,  //    ({ … })   redux }) .catch((error) => { … } );  } 

I really hope that this article was not a waste of time for you, and you found in it something useful for yourself!

- Best promotion service on reddit, bitcointalk and medium: reddit-marketing.pro

Source: https://habr.com/ru/post/341464/


All Articles