首页 > 解决方案 > Angular 应用程序中的声明式和反应式方法之间的摩擦

问题描述

这是我定期面临的一个问题,当我的应用程序由声明性组件组成时(因此它们的模板完全可以通过其属性的值来预测),但在某些时候,有一个主题以一种反应性的方式推送一个新值。

假设我有这样的东西:基于数组元素的组件列表。

<hello *ngFor="let h of helloComponents"></hello>

hello 组件从服务订阅了 BehaviorSubject。

在某些时候(例如,当单击按钮时),behaviourSubject 会发出一个新值,但数组也会更新。

事件顺序如下:

  1. 主题发出一个新值
  2. 订阅主题的组件接收新值
  3. 数组被更新,新组件被初始化,它们从主题接收新值作为第一个值

问题是旧组件在销毁之前收到了值,因此它们可能会运行我不希望它们执行的代码,因为它们在第 3 点被销毁。

如果我首先更新数组,然后从主题中推送一个新值,那么场景不会改变。

我找到了 2 个修复:

A. 使用 setTimeout 确保在旧组件已被 Angular Change Detection 销毁时主体发出新值。但我不知道这个解决方案有多强大......

this.myarray= [4, 5];
setTimeout(() => subject.next(new value));

B.使用observeOn(asyncScheduler)

this.stateService.state$.pipe(
        observeOn(asyncScheduler)
    ).subscribe(
      state => console.log(`helloComponent ${this.id}, state: ${state}`)
    )

但我真的是 Rxjs 调度程序的新手,我不知道这是一个好方法还是有更好的选择。

这是堆栈闪电战...打开控制台

有任何想法吗?

标签: angularrxjsreactive-programmingscheduler

解决方案


我将跟踪与手动更改检测结合使用(可能看起来很粗糙,但您helloComponents在与从服务触发更新相同的事件循环滴答中手动更新数组),它似乎工作:

import { Component, ChangeDetectorRef } from '@angular/core';
import { StateService } from './state.service';

@Component({
  selector: 'my-app',
  template: `<hello *ngFor="let h of helloComponents, trackBy: trackById" [id]="h"></hello> <button (click)="action()">action</button>`
})
export class AppComponent {
  name = 'Angular';
  helloComponents = [1, 2, 3];

constructor(private stateService: StateService, private ref: ChangeDetectorRef) {}

  action() {
    this.helloComponents = [4, 5];
    this.ref.detectChanges();
    this.stateService.action();
  }

  trackById = id => id;
}

堆栈闪电战: https ://stackblitz.com/edit/angular-e9zfoq ?file=src/app/app.component.ts


推荐阅读