使用leancloud實現迭代查詢

backlight發表於2018-07-25

背景

手機APP業務中資料查詢大多為滾動觸底載入更多資料,如果使用傳統的分頁查詢當遇到以下場景時就會出現資料錯誤:

例如某個APP頁面資料展示按新增時間降序排序,預設每次請求十條資料

當使用者A查詢第一頁資料(資料1-10)後,使用者B新增了一條新資料,此時使用者A操作觸發載入更多資料,此時請求第二頁資料,由於使用者B新增了一條資料N1,按照資料按降序排列 則會把使用者A查到第一頁的最後一條資料10後推到第二頁,此時A請求的第二頁資料則會再次出現之前已經出現過的資料10,頁面就會重複渲染資料10.這樣的結果顯示不是使用者需要的。

使用leancloud實現迭代查詢

為了解決該問題,所以採用迭代器來執行查詢操作

構造迭代器

迭代器生成器介紹

LeancloudHelp 類中增加生成迭代器函式createIterator

total為要查詢資料的總條數,在第一次查詢後得到具體的總記錄數

/**
   * 迭代查詢
   * @param {*} objName 物件名
   * @param {*} params 查詢引數列表 約定迭代查詢需要的引數(日期型別)放在第一位
   * @param {*} sorts 排序列表 只支援單個日期型別欄位排序
   * @param {*} limit 每次查詢數量
   */
  static createIterator(objName, params, sorts, limit = 10) {
    let total = limit
    let i = 0
    return {
      next: async (lastCreatedAt) => {
        const done = (i >= total)
        let data
        if (params) {
          params[0].value = new Date(lastCreatedAt)
        }
        await LeancloudHelp.getList(objName, params, limit, 1, sorts, i === 0).then((res) => {
          data = res.data
          if (i === 0) {
            total = res.total
          }
        }).catch((error) => {
          throw error
        })
        i += limit
        const value = done ? undefined : data
        return {
          done,
          value,
        }
      },
    }
  }
複製程式碼

迭代器呼叫

query 為頁面查詢方法, createIterator為要實現迭代查詢的類在這裡構造相關的查詢引數和排序方式

首次呼叫query方法時要先建立迭代器物件,然後預設執行一次迭代查詢。

query = () => {
    console.log('iterator', this.state.iterator)
    if (!this.state.iterator) {
      const iterator = Notice.createIterator()
      this.setState({iterator}, () => {
        console.log('iterator', this.state.iterator)
        this.state.iterator.next(new Date()).then((res) => {
          console.log(res)
          if (!res.done) {
            if (res.value.length) {
              this.setState({lastCreatedAt: res.value[res.value.length - 1].createdAt})
            }
          }
        }).catch((error) => {
          console.error(error)
        })
      })
    } else {
      this.state.iterator.next(this.state.lastCreatedAt).then((res) => {
        console.log(res)
        if (!res.done) {
          if (res.value.length) {
            this.setState({lastCreatedAt: res.value[res.value.length - 1].createdAt})
          }
        }
      }).catch((error) => {
        console.error(error)
      })
    }
  }

static createIterator(title) {
    const params = [
      {colName: 'createdAt', value: undefined, queryType: Enum.queryType.lessThan},
      {colName: 'title', value: title, queryType: Enum.queryType.contains},
    ]
    const sorts = [
      {sortWay: Enum.sortWay.descending, colName: 'createdAt'},
    ]
    const limit = 10
    return LeancloudHelp.createIterator('Notice', params, sorts, limit)
  }
}
複製程式碼

相關文章