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

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

问题描述

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

 文章:{
text:..
meta:{..}
user:{
id:user1,
username:..
}
}

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

$ p $ 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大约一个星期前,所以我可能仍然有一些误解。

解决方案



<当看到这个问题时,我发现问题与<$ c $当$ preserveSnapshot false 时,FirebaseListObservable 实现 - 默认行为。每当observable发出一个打开的快照数组时,数组元素就是不同的实例 - 即使元素本身没有改变。这导致了检测效率低得多。



A fix已被合并,并将被包含在下一个版本的AngularFire2中(也就是后面的版本 2.0.0-beta.7 ) - 应该很快



通过修复,如果使用Angular的 OnPush 变更检测,AngularFire2的 FirebaseListObservable 是非常快速和有效的DOM更新。



我通常将组件分成,其中容器组件包含可观察的元素,并且呈现组件使用 OnPush 变化检测。

T他的容器组件看起来像这样:
$ b

  import {Component} from@ angular / core ; 
从angularfire2导入{AngularFire,FirebaseListObservable};
$ b @Component({
selector:items-container,
template:`< items-component [items] =items | async>< items-component>`
})
export class ItemsContainer {

private items:FirebaseListObservable< any> ;;

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






这个表示性的组件看起来像这样: / b>

从@ angular / core导入{ChangeDetectionStrategy,Component,Input};

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



$ b $ p
$ b

通过这种安排,Angular的 OnPush code> change detection将确保只有实际更改的元素才会影响DOM更新。因此,即使长时间,滚动列表也会高效快速。另外一个技巧:使用限制查询的 FirebaseListObserable 当底层数据发生变化时,有时会发出两个值。例如,当一个新项目被添加到数据库中时,一个查询10个最近项目(使用 limitToLast:10 )的列表将会发出一个包含最近项目的数组删除,然后立即发出另一个最近添加的项目。如果不希望这两个数组中的第一个被发射,则可以使用 auditTime 操作符:

  importrxjs / add / operator / auditTime; 

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


In my application I have the following firebase posts structure:

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

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.

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.

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.

解决方案

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 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.

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

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[];
}

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.

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天全站免登陆