การแบ่งหน้าอย่างง่ายสำหรับการโหลดเนื้อหาเพิ่มเติมในขณะที่ยังคงฟังการอัปเดต

แรงจูงใจ

การเลื่อนแบบไม่มีที่สิ้นสุดเป็นฟังก์ชันที่ต้องการโดยทั่วไป โดยเฉพาะอย่างยิ่งในฟีดทุกประเภท ต้องมีการโหลดเนื้อหาเพิ่มเติมตามความต้องการในขณะที่ผู้ใช้เลื่อนดู สิ่งนี้อาจทำได้ง่ายเพียงพอหากเนื้อหาเป็นแบบคงที่ คุณเพียงแค่โหลด n รายการ และเมื่อผู้ใช้เลื่อนไปที่จุดสิ้นสุดของรายการเหล่านั้น คุณจะโหลดเพิ่มอีก n รายการ ทำซ้ำ. Firebase ให้ตัวอย่างที่ดีของ วิธีการทำสิ่งนี้ (ส่วนที่โหลดนี้ ไม่ใช่การเลื่อน)

แต่ถ้าคุณมีข้อมูลแบบไดนามิก และคุณต้องรับฟังการเปลี่ยนแปลงด้วย สิ่งที่ถูกเพิ่ม ลบ และแก้ไข สิ่งต่างๆ มีความซับซ้อนขึ้นเล็กน้อย และฉันไม่พบบทช่วยสอนหรือตัวอย่างเกี่ยวกับวิธีการทำ ดังนั้นหลังจากที่เข้าใจแล้ว ฉันจึงตัดสินใจสร้างมันขึ้นมา เพื่อความง่าย ฉันจะไม่กล่าวถึงวิธีการทริกเกอร์ (ปุ่ม การเลื่อน ฯลฯ) ฟังก์ชันเพื่อโหลดเนื้อหาเพิ่มเติม ทั้งนี้ขึ้นอยู่กับคุณ

พฤติกรรมที่ต้องการ

กรณีการใช้งานของฉันคือแอปแชท การแชทสามารถมีข้อความได้นับพันข้อความ ฉันไม่ต้องการโหลดทั้งหมดทุกครั้ง สิ่งที่ฉันต้องการคือสร้างผู้ฟังที่เริ่มต้นที่ข้อความ n ข้อความกลับ และสามารถขยายกลับด้วย n ข้อความได้ตลอดเวลา น่าเสียดายที่ Firebase ไม่มีคุณสมบัติดังกล่าว แต่สิ่งที่เราทำได้คือสร้าง Listener ที่เริ่มต้นที่ข้อความ n ข้อความกลับมา และแทนที่จะขยายออกไป เพียงสร้าง Listener อื่นสำหรับข้อความ n ถัดไป

หวังว่าภาพวาดจะสมเหตุสมผล ผู้ฟังคนแรกของเราจะฟังข้อความล่าสุดและข้อความใหม่ที่เข้ามา ผู้ฟังคนที่สองจะฟังข้อความ n ถัดไป คนที่สามสำหรับข้อความ n หลังจากนั้น และอื่นๆ เราสามารถเพิ่มผู้ฟังต่อกันได้จนกว่าเราจะอ่านข้อความทั้งหมดจนหมด

เราจะใช้ตัวเลือกแบบสอบถามที่มีประโยชน์ซึ่ง firebase มีให้: orderBy(), startAt(), endBefore() และ limit() ช่วยให้เรากำหนดลำดับ ขีดจำกัด และขอบเขตในการสืบค้นของเรา

หากต้องการใช้ startAt() และ endBefore() เราต้องส่งสแนปชอตเอกสารให้พวกเขา สิ่งนี้จะทำให้เราวางขอบเขตบนและล่างให้กับผู้ฟังของเรา ในการรับสแนปชอตเอกสาร อันดับแรกเราต้องสร้างการสืบค้นแบบครั้งเดียวแบบง่ายๆ โดยมีขีดจำกัด n เอกสาร เพื่อที่เราจะได้รับสแนปชอตเอกสารของข้อความที่เป็นข้อความ n ข้อความกลับมา (เช่น ข้อความที่ 50 สุดท้าย)

รหัส

ตกลงนี่คือส่วนที่คุณทุกคนมาที่นี่เพื่อ:

  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())
  }

ในการตั้งค่าผู้ฟังคนแรกที่เราเรียกว่า getMessages() และเพื่อโหลดข้อความเก่าๆ ที่เราเรียกว่า getMoreMessages() ฟังก์ชันทั้งสองเกือบจะเหมือนกัน ดังนั้นจึงสามารถรวมเป็นฟังก์ชันเดียวได้อย่างง่ายดาย แต่เพื่อความชัดเจนและความเรียบง่าย ฉันจึงแยกฟังก์ชันทั้งสองออกจากกัน

ข้อแตกต่างระหว่างสองฟังก์ชันที่ผู้ฟังคนแรกไม่ต้องการคือการใช้ endBefore() เนื่องจากขอบเขตการสิ้นสุดจะป้องกันไม่ให้ฟังข้อความใหม่ ผู้ฟังคนอื่นๆ ทั้งหมดจำเป็นต้องมีขอบเขตเริ่มต้นและสิ้นสุด โดยผู้ฟังแต่ละคนมีขอบเขตร่วมกัน (เช่น ขอบเขตเริ่มต้นของผู้ฟัง 2 คือขอบเขตสิ้นสุดของผู้ฟัง 3 [อ้างอิงถึงรูปวาด])

เราจัดผู้ฟังไว้ในอาร์เรย์เพื่อให้เราสามารถแยกออกทั้งหมดได้อย่างง่ายดายเมื่อเราปิดหน้าต่างแชท

หวังว่านี่จะช่วยคุณในการแบ่งหน้าแบบโต้ตอบหรือโหลดกลับ ฉันจะติดตามผลด้วยบทช่วยสอนเพื่อใช้สิ่งนี้ด้วยการเลื่อนแบบไม่มีที่สิ้นสุด (เมื่อฉันเข้าใจแล้ว 😜)