Penomoran halaman sederhana untuk memuat lebih banyak konten sambil tetap mendengarkan pembaruan

Motivasi

Pengguliran tak terbatas adalah fungsi yang sangat diinginkan, terutama di semua jenis umpan. Dibutuhkan lebih banyak konten untuk dimuat sesuai kebutuhan saat pengguna menggulir. Ini cukup sederhana jika kontennya statis. Anda cukup memuat n item, dan saat pengguna menggulir ke bagian akhir, Anda memuat n item lagi. Mengulang. Firebase memberikan contoh yang bagus tentang "bagaimana melakukan ini" (bagian pemuatan ini, bukan pengguliran).

Namun bagaimana jika Anda memiliki data dinamis, dan Anda juga perlu memperhatikan perubahannya. Hal-hal yang ditambahkan, dihapus dan diedit. Segalanya menjadi sedikit lebih rumit, dan saya tidak dapat menemukan tutorial atau contoh apa pun tentang cara melakukannya, jadi setelah mengetahuinya saya memutuskan untuk membuatnya. Untuk mempermudah, saya tidak akan membahas cara memicu (tombol, gulir, dll.) fungsi untuk memuat lebih banyak konten karena itu terserah Anda.

Perilaku yang diinginkan

Kasus penggunaan saya adalah aplikasi obrolan. Obrolan dapat berisi ribuan pesan di dalamnya. Saya tidak ingin memuat semuanya setiap saat. Yang saya inginkan adalah membuat pendengar yang dimulai dari pesan n pesan kembali, dan dapat diperluas kembali dengan n pesan kapan saja. Sayangnya Firebase tidak memiliki fitur seperti itu. Namun yang bisa kita lakukan adalah membuat pendengar yang dimulai dari pesan n pesan kembali, dan alih-alih memperluasnya, cukup buat pendengar lain untuk n pesan berikutnya.

Semoga gambarnya masuk akal. Pendengar pertama kita akan mendengarkan pesan terbaru, dan semua pesan baru yang masuk. Pendengar kedua akan mendengarkan n pesan berikutnya, pendengar ketiga untuk n pesan setelah itu, dan seterusnya. Kita dapat terus menambahkan pendengar satu sama lain hingga kita menyelesaikan seluruh kumpulan pesan.

Kami akan menggunakan pemilih kueri praktis yang disediakan firebase: orderBy(), startAt(), endBefore(), dan limit(). Mereka memungkinkan kami menentukan urutan, batasan, dan batasan pada kueri kami.

Untuk menggunakan startAt() dan endBefore() kita harus meneruskan snapshot dokumen kepada mereka. Ini akan memungkinkan kita memberi batas atas dan bawah pada pendengar kita. Untuk mendapatkan cuplikan dokumen, pertama-tama kita harus melakukan kueri satu kali sederhana dengan batas n dokumen sehingga kita bisa mendapatkan cuplikan dokumen dari pesan yaitu n pesan kembali (misalnya pesan terakhir ke-50).

Kode

Oke, inilah bagian tujuan Anda semua di sini:

  var messages = [] 
  var listeners = []    // list of listeners
  var start = null      // start position of listener
  var end = null        // end position of listener
  function getMessages(chatId) {
    // query reference for the messages we want
    let ref = db.collection('chats').doc(chatId)
    .collection('messages')
    // single query to get startAt snapshot
    ref.orderBy('createdAt', 'desc')
    .limit(50).get()
    .then((snapshots) => {
    
    // save startAt snapshot
    start = snapshots.docs[snapshots.docs.length - 1]
    // create listener using startAt snapshot (starting boundary)    
    let listener = ref.orderBy('createdAt')
      .startAt(start)
      .onSnapshot((messages) => {
        // append new messages to message array
        messages.forEach((message) => {
          // filter out any duplicates (from modify/delete events)         
          messages = messages.filter(x => x.id !== message.id)
          messages.push(message.data())
        })
      })
      // add listener to list
      listeners.push(listener)
    })
  }
    function getMoreMessages(chatId) {
    let ref = db.collection('chats').doc(chatId)
    .collection('messages')
    // single query to get new startAt snapshot
    ref.orderBy('createdAt', 'desc')
    .startAt(start)
    .limit(50).get()
    .then((snapshots) => {
     // previous starting boundary becomes new ending boundary
      end = start
      start = snapshots.docs[snapshots.docs.length - 1]
      // create another listener using new boundaries     
      let listener = ref.orderBy('createdAt')
      .startAt(start).endBefore(end)
      .onSnapshot((messages) => {
        messages.forEach((message) => {
          messages = messages.filter(x => x.id !== message.id)
          messages.push(message.data())
        })
      })
      listeners.push(listener)
    })
  }
  // call to detach all listeners
  function detachListeners() {
    listeners.forEach(listener => listener())
  }

Untuk menyetel pendengar pertama, kami memanggil getMessages() dan untuk memuat pesan lama apa pun kami memanggil getMoreMessages(). Kedua fungsi tersebut hampir identik sehingga sebenarnya dapat dengan mudah digabungkan menjadi satu fungsi tetapi untuk kejelasan dan kesederhanaan saya memisahkannya.

Satu-satunya perbedaan antara kedua fungsi tersebut adalah pendengar pertama tidak memerlukan dan menggunakan endBefore() karena batas akhir akan mencegahnya mendengarkan pesan baru. Semua pendengar lainnya memerlukan batasan awal dan akhir. Dengan setiap pendengar berbagi batasnya (misalnya batas awal pendengar 2 adalah batas akhir pendengar 3 [lihat gambar])

Kami menempatkan pendengar dalam sebuah array sehingga kami dapat dengan mudah melepaskan semuanya ketika kami menutup jendela obrolan.

Semoga ini membantu Anda dengan pagination reaktif atau back-loading Anda. Saya akan pastikan untuk menindaklanjuti tutorial untuk menggunakan ini dengan pengguliran tak terbatas (setelah saya mengetahuinya 😜)