Firebase Angular2 - 如何在没有太多开销的情况下查询和呈现列表 [英] Firebase Angular2 - how to query and render lists without too much overhead

查看:29
本文介绍了Firebase Angular2 - 如何在没有太多开销的情况下查询和呈现列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的应用程序中,我有以下 firebase 帖子结构:

In my application I have the following firebase posts structure:

posts: {
    text: ".."
    meta: {..}
    user: {
        id: "user1",
        username: ".."
    }
}

我正在使用 angularfire2.因此,为了获取特定用户发布的所有帖子,我运行以下查询:

I'm using angularfire2. So, to get all posts posted by specific user, I run the following query:

this.userPosts$ = this.af.database.list('/posts', {
    query: {
      orderByChild: 'user/id',
      equalTo: userId
    }
  }).map( (posts) => {
    return posts.map(post => Post.unpack(post));
  }).publishReplay(1).refCount();

我听说它效率不高,因为每次发生变化(即使是在一个帖子中),整个列表都会重新加载,从而重新呈现.由于我在我的应用中喜欢和不喜欢,这会经常发生.基本上每次有人喜欢一个帖子时,如果我没记错的话,整个列表都会为每个用户重新加载.

I've heard that it's not very efficient, since every time something changes (even in a single post), the whole list is reloaded and, thus, re-rendered. And since I have likes and dislikes in my app, this is gonna happen pretty often. Basically every time someone likes a post, the whole list is reloaded for every user, if I'm not mistaken.

我知道有一种方法可以在侦听 firebase 事件时维护列表的本地副本:child_ added"、child_removed"和child_changed".但是,如果我将这些事件附加到查询列表中,它们将在每次原始帖子列表整体发生变化时触发.

I know that there is a way to maintain a local copy of the list while listening to firebase events: "child_added", "child_removed" and "child_changed". However, if I attach these events to the queried list, they are going to fire each time something changes in the original posts list as a whole.

所以,我在考虑在这里采取什么方法.如果这是唯一的好选择,我可能会将帖子数据复制到 firebase 中的user_posts"列表中.但是,使用这种方法,我觉得查询变得几乎毫无用处,并且失去了灵活性.我大约一周前才开始使用 firebase,所以我可能还有一些误解.

So, I am thinking what approach to take here. I might duplicate posts data into "user_posts" list in firebase if it is the only good choice. However, with this approach I feel that querying becomes almost useless and I lose flexibility. I started to use firebase just about a week ago, so I might still have some misunderstandings.

推荐答案

在调查这个问题时,我发现一个问题FirebaseListObservablepreserveSnapshotfalse 时的实现 - 默认行为.每次 observable 发出一组未包装的快照时,数组元素都是不同的实例——即使元素本身没有改变.这导致变更检测的效率大大降低.

When looking into this question, I discovered an issue with the FirebaseListObservable implementation when preserveSnapshot was false - the default behaviour. Each time the observable emitted an array of unwrapped snapshots, the array elements were different instances - even if the elements themselves had not changed. And this resulted in much less efficient change detection.

A 修复已合并,并将包含在下一版本的 AngularFire2 中(即 2.0.0-beta.7 之后的版本) - 应该很快.

A fix has been merged and will be included in the next release of AngularFire2 (that is, the release that follows 2.0.0-beta.7) - which should be soon.

修复后,如果使用 Angular 的 OnPush 更改检测,AngularFire2 的 FirebaseListObservable 在 DOM 更新方面非常快速和高效.

With the fix, if Angular's OnPush change detection is used, AngularFire2's FirebaseListObservable is very fast and efficient regarding DOM updates.

我通常将组件拆分为容器和展示组件,容器组件保存可观察对象,展示组件使用 OnPush 更改检测.

I usually split the components into container and presentational components, with the container component holding the observable and with the presentational component using OnPush change detection.

容器组件看起来像这样:

The container component would look something like this:

import { Component } from "@angular/core";
import { AngularFire, FirebaseListObservable } from "angularfire2";

@Component({
  selector: "items-container",
  template: `<items-component [items]="items | async"></items-component>`
})
export class ItemsContainer {

  private items: FirebaseListObservable<any>;

  constructor(private angularFire: AngularFire) {
    this.items = angularFire.database.list("some/fast-changing/data", {
      query: {
        limitToLast: 1000
      }
    });
  }
}

展示组件看起来像这样:

And the presentational component would look something like this:

import { ChangeDetectionStrategy, Component, Input } from "@angular/core";

@Component({
  changeDetection: ChangeDetectionStrategy.OnPush,
  selector: "items-component",
  template: `
    <ul>
      <li *ngFor="let item of items">{{ item | json }}</li>
    </ul>
  `
})
export class ItemsComponent {
  @Input() items: any[];
}

通过组件的这种排列,Angular 的 OnPush 更改检测将确保只有实际更改的元素才会影响 DOM 更新.因此,即使很长,滚动列表也将高效且快速.

With this arrangement of components, Angular's OnPush change detection will ensure that only the elements that have actually changed will effect DOM updates. So even long, scrolling lists will be efficient and fast.

另一个提示:使用限制查询的 FirebaseListObserable 有时会在基础数据更改时发出两个值.例如,当一个新项目被添加到数据库时,一个查询最近 10 个项目的列表(使用 limitToLast: 10)将发出一个数组,其中删除了最近的项目,然后立即发出另一个添加了最新的项目.如果您不想发出这两个数组中的第一个,可以使用 auditTime 运算符:

Another tip: a FirebaseListObserable that uses a limit query will sometimes emit two values when the underlying data changes. For example, when a new item is added to the database, a list that queries the 10 most recent items (using limitToLast: 10) will emit an array with the least recent item removed and will then immediately emit another with the most recent item added. If you don't want the first of those two arrays to be emitted, you can use the auditTime operator:

import "rxjs/add/operator/auditTime";

this.items = angularFire.database.list("some/fast-changing/data", {
  query: {
    limitToLast: 10
  }
})
.auditTime(0);

这篇关于Firebase Angular2 - 如何在没有太多开销的情况下查询和呈现列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆