【问题标题】:Angular 6 - How to stop infinite polling in subscribe()Angular 6 - 如何在订阅()中停止无限轮询
【发布时间】:2019-04-23 11:34:35
【问题描述】:

所以我想根据列表中的项目数是否大于 3 来显示一个图标。我正在使用这个 getProjects() 函数,我需要订阅它才能获取数据。我在订阅时设置了一个布尔值来检查列表中的项目数量,然后在我的 HTML 中,我使用 ngIf 来显示基于布尔值的图标。我能够让它正确显示,但是,我想我会不断地在我的订阅中轮询,并一遍又一遍地设置这个布尔值,因为它让我的网页运行得非常慢。

我已经尝试过 take(1) 方法,该方法似乎不会停止订阅,并将其设置为组件内的“this.variable”范围。我目前正在使用事件发射器,但这也不起作用。

这是我目前的代码,

我订阅的函数(在不同的组件中):

getProjects(): Observable<ProjectInterfaceWithId[]> {
    const organizationId = localStorage.getItem('organizationId');
    return this.firestoreService.collection('organizations').doc(organizationId)
      .collection('projects').snapshotChanges()
      .pipe(
        map(actions => actions.map(a => {
          const data = a.payload.doc.data() as ProjectInterface;
          const id = a.payload.doc.id;
          return {id, ...data} as ProjectInterfaceWithId;
        })),
        map(list => {
          if (list.length !== 0) {
            this.buildProjectLookup(list);
            this.projects = list;
            return list;
          }
        })
      );
  }

我用来获取数据和设置布尔值的函数:

@Input() toggle: boolean;
@Output() iconStatus = new EventEmitter();

displayIcon() {
    this.projectService.getProjects()
      .pipe(take(1))
      .subscribe(
        list => {
          if(list.length >= 3){
              this.toggle = true;
              this.iconStatus.emit(this.toggle);
          }
        });
  }

HTML:

<i *ngIf="displayIcon()" class="material-icons">list</i>

有没有什么办法让我只检查一次列表长度,这样我就不会陷入这个订阅循环?提前谢谢!

【问题讨论】:

    标签: html angular event-handling parent-child infinite-loop


    【解决方案1】:

    看起来可能是由于 ngIf 引用了displayIcon() 方法而发生的。

    每次更改检测在您的组件中运行时,都会调用此方法。如果您的组件使用默认更改检测,这将非常频繁。

    更多信息请参见https://blog.angular-university.io/how-does-angular-2-change-detection-really-work/

    解决此问题的一种方法是让 ngIf 改为引用一个变量。 例如,您可以使用

    设置 projects$ observable
    this.projects$ = this.projectService.getProjects()
          .pipe(
             take(1),
             tap(projects => this.iconStatus.emit(projects.length >= 3))
          );
    

    这个 observable 应该在你的 ngOnInit() 方法中被实例化。 然后在你的模板中你可以使用

    &lt;i *ngIf="(projects$ | async)?.length &gt;= 3" class="material-icons"&gt;list&lt;/i&gt;

    【讨论】:

    • ohhhh 好的太棒了,这有助于解决性能问题,这完全有道理,你不想把它绑定到一个方法上。但是我遇到了一个 bug,project.length 总是发出 3,所以这个语句总是正确的......你认为这是在 ngoninit 中使用它的情况,所以当我更改为 a 时它不会更新我的项目列表不同的组件有不同的项目?
    • 什么规定应该加载哪些项目?是否通过路由中的参数,例如从 route company/google/projects 导航到 route company/facebook/projects 应该重新获取项目吗?如果是这样,您将需要订阅 ActivatedRoute 的 params 变量并重新获取订阅中的项目。如果我误解了你的意思,请告诉我
    • 所以我有组织,每个组织都有自己的项目集。是的,所以路由就像 home/org-overview/org-dashboard,每个组织都有自己的项目列表。目前,我上面列出的方法是我获取项目列表的唯一方法。我对订阅 params 变量和重新获取的意思感到困惑,我还是 rxjs 编程的新手哈哈
    • 关于订阅参数:如果您将 ActivatedRoute 的实例注入到组件构造函数中,则该实例具有可观察的属性(称为参数)。如果您订阅此 observable,您可以在订阅中定义代码,该代码将在每次更改路由参数之一时运行。您可以做的另一件事是在此参数 observable 上使用 switchMap 运算符调用后端。我在这里整理了一个小例子,如果您有任何问题,请告诉我:stackblitz.com/edit/angular-6n3nn4
    猜你喜欢
    • 2019-12-15
    • 1970-01-01
    • 1970-01-01
    • 2023-02-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多