简体   繁体   English

使用 vuex 并将新数据附加到 state 时对 firestore 数据进行分页

[英]Paginating firestore data when using vuex and appending new data to the state

I implemented the following to display a paginated query (this was suggested by Tony O'Hagan in this post: How to get the last document from a VueFire query ):我实现了以下内容来显示分页查询(这是 Tony O'Hagan 在这篇文章中提出的: 如何从 VueFire 查询中获取最后一个文档):

bindUsers: firestoreAction(({ bindFirestoreRef }) => {
  return bindFirestoreRef('users', 
      Firebase.firestore().collection('users').limit(8), { serialize })
}),
bindMoreUsers: firestoreAction(context => {
  return context.bindFirestoreRef('users', Firebase.firestore().collection('users').startAfter(context.state.users[context.state.users.length - 1]._doc).limit(8), { serialize })
})

When the user scrolls to the end of the page, I call bindMoreUsers which updates the state.users to the next set of 8 documents.当用户滚动到页面末尾时,我调用 bindMoreUsers 将 state.users 更新为下一组 8 个文档。 I need to be able to append to the state.users as opposed to overwrite the original set of 8 documents.我需要能够将 append 转换为 state.users,而不是覆盖原来的 8 个文档集。 How can I do this?我怎样才能做到这一点?

Confession: I've not yet implemented pagination on my current app but here's how I'd approach it.忏悔:我还没有在我当前的应用程序上实现分页,但这就是我将如何处理它。

In my previous answer I explained how to keep references to the Firestore doc objects inside each element of the state array that is bound by VuexFire or VueFire.在我之前的回答中,我解释了如何在受 VuexFire 或 VueFire 绑定的 state 数组的每个元素内保留对 Firestore doc对象的引用。 In Solution #1 below we use these doc objects to implement Firestore's recommended cursor based pagination of a query result sets using startAfter(doc) query condition instead of the slower more expensive offset clause.在下面的解决方案 #1 中,我们使用这些 doc 对象来实现 Firestore 推荐的基于 cursor 的查询结果集的分页,使用startAfter(doc)查询条件而不是更慢更昂贵的offset子句。

Keep in mind that since we're using Vuexfire/Vuefire we're saying that we wish to subscribe to live changes to our query so our bound query will define precisely what ends up in our bound array.请记住,由于我们使用的是 Vuexfire/Vuefire,我们说我们希望订阅对查询的实时更改,因此我们的绑定查询将准确定义绑定数组中的最终结果。

Solution #1 .解决方案#1 Paging forward/backward loads and displays a horizontal slice of the full dataset (our bound array maintains the same size = page size).向前/向后分页加载并显示整个数据集的水平切片(我们的绑定数组保持相同的大小 = 页面大小)。 This is not what you requested but might be a preferred solution given the Cons of other solutions.这不是您所要求的,但考虑到其他解决方案的Cons ,这可能是首选解决方案。

  • Pros : Server: For large datasets, this pagination query will execute with least cost and delay.优点:服务器:对于大型数据集,此分页查询将以最少的成本和延迟执行。
  • Pros : Client: Maintains a small in memory footprint and will render fastest.优点:客户:在 memory 中保持较小的占用空间,并且渲染速度最快。
  • Cons : Pagination will likely not feel like scrolling.缺点:分页可能不会像滚动一样。 UI will likely just have buttons to go fwd/backward. UI 可能只有 go 前进/后退按钮。
  • Page Forward : Get the doc object from the last element of our state array and apply a startAfter(doc) condition to our updated view query that binds our array to the next page. Page Forward : 从 state 数组的最后一个元素中获取doc object 并将startAfter(doc)条件应用于我们更新的视图查询,将我们的数组绑定到下一页。
  • Page Backward : Bit Harder!向后翻页:再难一点! Get the doc object from the first element of our bound state array.从我们绑定的 state 数组的第一个元素中获取doc object。 Run our page query with startAfter(doc), limit (1), offset(pagesize-1) and reverse sort order.使用 startAfter(doc)、limit (1)、offset(pagesize-1) 和反向排序顺序运行我们的页面查询。 The result is the starting doc (pageDoc) of the previous page.结果是上一页的起始文档(pageDoc)。 Now use startAfter(pageDoc) and forward sort order and limit(pageSize) to rebind the state array (same query as Page Forward but with doc = pageDoc).现在使用startAfter(pageDoc)转发排序顺序和 limit(pageSize) 重新绑定 state 数组(与 Page Forward 相同的查询,但 doc = pageDoc)。

NOTE: In the general case, I'd argue that we can't just keep the pageDoc values from previous pages (to avoid our reverse query) since we're treating this as a 'live' update filtered list so the number of items still remaining from previous pages could have radically changed since we scrolled down.注意:在一般情况下,我认为我们不能只保留以前页面的 pageDoc 值(以避免我们的反向查询),因为我们将其视为“实时”更新过滤列表,因此项目数自从我们向下滚动以来,仍然保留在以前的页面中可能已经发生了根本性的变化。 Your specific application might not expect this rate of change so perhaps keeping past pageDoc values would be smarter.您的特定应用程序可能不会期望这种变化率,因此保留过去的 pageDoc 值可能会更聪明。

Solution #2 .解决方案#2 Paging forward, extends the size of the query result and bound array.向前分页,扩展查询结果和绑定数组的大小。

  • Pros : UX feels like normal scrolling since our array grows.优点:用户体验感觉就像正常滚动,因为我们的数组增长了。

  • Pros : Don't need to use serializer trick since we're not using startAfter() or endBefore()优点:不需要使用serializer程序,因为我们没有使用startAfter()endBefore()

  • Cons : Server: You're reloading from Firestore the entire array up to the new page every time you rebind to a new page and then getting live updates for growing array.缺点:服务器:每次重新绑定到新页面时,您都会从 Firestore 将整个阵列重新加载到新页面,然后获取不断增长的阵列的实时更新。 All those doc reads could get pricey!所有这些文档阅读都可能变得昂贵!

  • Cons : Client: Rendering may get slower as you page forward - though shadow DOM may fix this.缺点:客户端:当您向前翻页时,渲染可能会变慢 - 尽管影子 DOM 可能会解决这个问题。 UI might flicker as you reload each time so more UI magic tricks needed (delay rendering until array is fully updated). UI 可能会在您每次重新加载时闪烁,因此需要更多的 UI 魔术技巧(延迟渲染直到数组完全更新)。

  • Pros : Might work well if we're using an infinite scrolling feature.优点:如果我们使用无限滚动功能,可能会很好用。 I'd have to test it.我得测试一下。

  • Page Forward : Add pageSize to our query limit and rebind - which will re-query Firestore and reload everything. Page Forward :将pageSize添加到我们的查询限制并重新绑定 - 这将重新查询 Firestore 并重新加载所有内容。

  • Page Backward : Subtract pageSize from our query limit and rebind/reload (or not.). Page Backward :从我们的查询限制中减去pageSize并重新绑定/重新加载(或不重新加载)。 May also need to update our scroll position.可能还需要更新我们的滚动位置。

Solution #3 .解决方案#3 Hybrid of Solution #1 and #2.解决方案#1 和#2 的混合。 We could elect to use live Vuexfire/Vuefire binding for just a slice of our query/collection (like solution #1) and use a computed function to concat it with an array containing the pages of data we've already loaded.我们可以选择使用实时 Vuexfire/Vuefire 绑定来处理我们的查询/集合的一部分(如解决方案 #1),并使用计算的 function 将它与包含我们已经加载的数据页面的数组连接起来。

  • Pros : Reduces the Firestore query cost and query delay but now with a smooth scrolling look and feel so can use Infinite scrolling UI.优点:降低了 Firestore 查询成本和查询延迟,但现在具有平滑的滚动外观和感觉,因此可以使用无限滚动 UI。 Hand me a Koolaid!给我一杯Koolaid!
  • Cons : We'll have to try to keep track of which part of our array is displayed and make that part bound and so live updated.缺点:我们将不得不尝试跟踪我们数组的哪个部分被显示,并使该部分绑定并实时更新。
  • Page Forward/Backward: Same deal as Solution #1 for binding the current page of data, except we now have to copy the previous page of data into our non-live array of data and code a small computed function to concat() the two arrays and then bind the UI list to this computed array.向前/向后翻页:与解决方案#1 相同的处理方式,用于绑定当前数据页,除了我们现在必须将前一页数据复制到我们的非实时数据数组中,并将一个小的计算 function 编码到concat()两者arrays 然后将 UI 列表绑定到此计算数组。

Solution #3a We can cheat and not actually keep the invisible earlier pages of data.解决方案#3a我们可以作弊,而不是真正保留不可见的早期数据页面。 Instead we just replace each page with a div (or similar) of the same height;) so our scrolling looks we've scrolled down the same distance.相反,我们只是用相同高度的div (或类似的)替换每个页面;)所以我们的滚动看起来我们已经向下滚动了相同的距离。 As we scroll back we'll need to remove our sneaky previous page div and replace it with the newly bound data.当我们向后滚动时,我们需要删除我们偷偷摸摸的上一页div并将其替换为新绑定的数据。 If you're using infinite scrolling, to make the scrolling UX nice and smooth you will need to preload an additional page ahead or behind so it's already loaded well before you scroll to the page break.如果您正在使用无限滚动,为了使滚动 UX 美观流畅,您需要在前面或后面预加载一个额外的页面,以便在滚动到分页符之前它已经加载好。 Some infinite scroll APIs don't support this.一些无限滚动 API 不支持这一点。

Solution #1 & #3 probably needs a Cookbook PR to VueFire or a nice MIT'd / NPM library.解决方案 #1 和 #3 可能需要 VueFire 的Cookbook PR或一个不错的 MIT'd / NPM 库。 Any takers?有接盘侠吗?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM