【问题标题】:Angular5: Clarification on Observables and SubscriptionAngular5:关于 Observables 和订阅的说明
【发布时间】:2018-03-31 02:42:43
【问题描述】:

我目前正在尝试在向下滚动时动态加载数据,这样它就不必一次加载,而是在用户滚动时逐个加载。如下图:

就目前而言,在初始化包含右侧数学信息的组件时,我使用订阅将屏幕上显示的定理数量绑定到我的服务指示的内容。这样做是这样的:

bible.component.ts

import { Component, OnInit, AfterContentChecked } from '@angular/core';
import { BibleService } from './bible.service';
import {Theorem} from '../../model/theorem';
import {ElementRef, ViewChild} from '@angular/core';

@Component({
  selector: 'app-bible',
  templateUrl: './bible.component.html',
  styleUrls: ['./bible.component.scss']
})
export class BibleComponent implements OnInit {

  allTheorems: Theorem[];
  filtered: Theorem[];
  @ViewChild('theoremList') elementView: ElementRef;

  constructor(private service: BibleService) {}

  ngOnInit() {
    this.service.findAllTheorems()
      .subscribe(
        theorems => this.allTheorems = this.filtered = theorems
      );
  }

  search(search: string) {
    this.filtered = this.allTheorems.filter(theorem =>
      theorem.rule.includes(search) ||
       (theorem.name && theorem.name.toLowerCase().includes(search.toLowerCase())
    ));
  }
}

bible.service.ts

import {Observable} from 'rxjs/Observable';
import {Theorem} from '../../model/theorem';
import {AngularFireDatabase} from 'angularfire2/database';
import {Injectable, OnInit} from '@angular/core';
import {Subject} from 'rxjs/Subject';

@Injectable()
export class BibleService {

  pageSize = 10;
  private pageSizeSubscription;
  pageSizeChange: Subject<number> = new Subject<number>();

  constructor(private af: AngularFireDatabase) {}

  findAllTheorems(): Observable<Theorem[]> {

    return this.af.list('theorems', ref => {
      return ref.limitToFirst(this.pageSize).orderByKey();
    }).valueChanges().map(Theorem.fromJsonList);

    // return this.af.list('theorems').valueChanges().map(Theorem.fromJsonList);

  }

  updatePageSize(num) {
    this.pageSizeChange.next(num);
  }

}

所以在初始化时的 bible.component.ts 中,我调用名为“findAllTheorems”的服务函数并订阅返回值,这样我的两个 Theroem 数组就会被返回值填充。 旁注我对此订阅发生的情况的解释是否正确?这是否意味着如果“findAllTheorems”返​​回的值发生变化,那么我的数组将动态更新?

无论如何,我想知道如何在我的服务中动态更改 pageSize 的值并让它更新页面,以便在用户向下滚动时显示更多定理?这是最好的方法吗? 总体当用户向下滚动时,将更多项目动态加载到列表中的最佳方法是什么,以便每次他们点击底部 10 更多项目加载到底部?我也有一个观察者,当 div 的底部被击中时,我会记录到控制台,这意味着我可以调用一个函数来添加更多的定理。

另外,findAllTheorems 是一个可观察的究竟是什么意思?这本质上是说这个函数是开放订阅的,以便其他函数或变量可以随时观察它输出的内容以保持最新状态?

感谢您的帮助。

【问题讨论】:

    标签: angular scroll observable subscription


    【解决方案1】:

    是的,您对订阅的解释是正确的,但是您似乎没有将订阅存储在任何地方,这意味着您在组件销毁后无法取消订阅。这会导致内存泄漏。

    试试这样的:

     private subscription: Subscription;
    
     ngOnInit() {
        this.subscription = this.service.findAllTheorems()
          .subscribe(
            theorems => this.allTheorems = this.filtered = theorems
          );
      }
    
      ngOnDestroy() {
        this.subscription.unsubscribe();
      }
    

    如果您不想强制处理订阅,请尝试使用异步管道。它将为您处理订阅。查看docs

    至于无限滚动和动态加载内容,我会使用Intersection Observer。确保包含一个 polyfill,因为目前全球浏览器支持率约为 75%。

    AngularFire 的基本实现是这样的:

    1. 创建当用户滚动到页面底部时发出的 InfiniteScroll 指令。
    2. 每次发出 InfiniteScroll 指令时,使用 AngularFire 的 dynamic querying 运行一个新查询。

    【讨论】:

    • 感谢您的帮助,我将致力于实现动态查询。我理解为什么会出现内存泄漏以及为什么我需要取消订阅,但这是在 ngOnInit() 上执行此操作的最佳位置吗?因为如果我需要在组件启动时更新值,如果我立即在 ngOnInit() 上取消订阅,它不会继续跟踪更改吗?如果我是对的,当应用程序关闭时(例如当用户关闭选项卡或退出或我结束服务时)取消订阅的最佳方式是什么?再次感谢。
    • 啊这是我的错字。您需要在ngOnInit() 订阅并在ngOnDestroy() 取消订阅。我已经编辑了我的答案。
    猜你喜欢
    • 1970-01-01
    • 2017-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    • 2022-01-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多