【问题标题】:Firebase Angular2 - how to query and render lists without too much overheadFirebase Angular2 - 如何在没有太多开销的情况下查询和呈现列表
【发布时间】:2017-02-11 13:34:51
【问题描述】:

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

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

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

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

我听说它效率不高,因为每次发生变化时(即使是在单个帖子中),整个列表都会重新加载,因此会重新渲染。而且由于我的应用程序中有好恶,这会经常发生。如果我没记错的话,基本上每次有人喜欢帖子时,都会为每个用户重新加载整个列表。

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

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

【问题讨论】:

  • 我已经通过长列表了解了 AngularFire2 的行为。如果我是你,我不会为此付出任何努力,因为实现速度非常快,并且在使用 preserveSnapshot 选项时与 Angular 的更改检测配合得很好。只有当未指定该选项时,整个列表才会出现变化。对此应该有一些可以做的事情,我将考虑提出问题并提交 PR。之后,我会回答你的问题。

标签: database angular firebase firebase-realtime-database angularfire2


【解决方案1】:

在调查这个问题时,我发现 an issue 与 FirebaseListObservable 实现时 preserveSnapshot 是 false - 默认行为。每次 observable 发出一组展开的快照时,数组元素都是不同的实例——即使元素本身没有改变。这导致变更检测的效率大大降低。

fix has been merged 并将包含在 AngularFire2 的下一个版本(即 2.0.0-beta.7 之后的版本)中 - should be soon。

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

我通常将组件拆分为container and presentational components,容器组件保存可观察对象,而展示组件使用OnPush 更改检测。

容器组件看起来像这样:

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

演示组件看起来像这样:

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 更新。因此,即使很长,滚动列表也会高效且快速。

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

import "rxjs/add/operator/auditTime";

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-02-11
    • 2019-06-22
    • 2013-06-21
    • 2016-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-24
    相关资源
    最近更新 更多