通过异步管道重新分配可观察到的值

时间:2019-05-03 10:46:49

标签: angular

比方说,在我的 Component 中,我有一个Observable字段,可通过 Service 使用HttpClient

进行检索
@Component(...)
export class MyComponent {
  items$: Observable<readonly Item[]>;

  ngOnInit() {
    this.items$ = this.findItems();
  }

  private findItems() {
    return this.service
      .getItems(...)
      .pipe(
        // Other code omitted
        toArray<Item>()
      );
  }
}

<app-items [items]="items$ | async"></app-items>

然后,当在MyComponent内部执行操作时,我需要刷新items$列表,因此我将 Service

称为
onButtonPressed() {
  this.items$ = this.findItems();
}

问题是,Async管道是否会自动订阅新的Observable
考虑到我正在使用detectChanges()策略,是否需要要求OnPush
最重要的是,这是正确的方法吗?

4 个答案:

答案 0 :(得分:1)

要回答我自己的问题,是的,如果使用ChangeDetectorRef#detectChanges变更检测策略,则需要调用OnPush

constructor(
  ...
  private readonly changeDetectorRef: ChangeDetectorRef
) {}

onButtonPressed() {
  this.items$ = this.findItems();
  this.changeDetectorRef.detectChanges();
}

似乎没有一种“更聪明”的方法,即使不使用第二个[Behavior]Subject


编辑:我注意到重新分配并调用detectChanges可能会导致闪烁。
最后,我选择了BehaviorSubject

private readonly items = new BehaviorSubject<readonly Item[]>([]);

constructor(...) {
  items$ = this.items.asObservable(); 
}

...

this.findItems().subscribe(items => this.items.next(items));

因此,不再需要重新分配。

答案 1 :(得分:1)

您可能要使用switchMap管道:

@Component(...)
export class MyComponent {
  items$: Observable<readonly Item[]>;

  updater$: Subject<void> = new Subject<void>();

  ngOnInit() {
    this.items$ = this.updater$
      .pipe(
        switchMap<void, Observable<Items[]>>(() => this.findItems())
      )
  }

  onButtonPressed(){
    this.updater$.next();
  }

  private findItems() {
    return this.service
      .getItems(...)
      .pipe(
        // Other code omitted
        toArray<Item>()
      );
  }
}

并仍然使用:

<app-items [items]="items$ | async"></app-items>

switchMap()允许您有一个“永不重新分配”的可观测值(updater$),对于此流上的每个发射率,它“切换”该观测值的发射值以发送结果内部函数,应该是可观察的。

在这里,每次调用updater$.next()时,它都会将发出的void“切换”到findItems()方法的结果(即您的项数组)中。

switchMapmergeMap之间的区别在于switchMap负责完成和关闭先前发出的可观察对象。如果您两次调用updater$.next(),则第二次调用switchMap将完成第一次调用findItems()返回的第一个可观察对象,并将其替换为此方法的新调用。

资料来源:
https://www.learnrxjs.io/operators/transformation/switchmap.html
https://blog.angular-university.io/rxjs-higher-order-mapping/

答案 2 :(得分:0)

  

异步管道会自动订阅新的Observable吗?

异步管道订阅Observable或Promise并返回其发出的最新值。当组件被销毁时,异步管道将自动退订,以避免潜在的内存泄漏。

  

考虑到我在OnPush上,我是否需要请求detectChanges()   策略?

您不需要。发出新值时,异步管道会将要检查的组件标记为更改。

这是正确的方法吗? 我看不出有什么害处,因为当组件被销毁时,订阅将自动取消订阅。

答案 3 :(得分:0)

这不是100%肯定的答案,因为它没有记录,但是我们可以从docs中的Promise管道处理async中获得一些线索。

greeting: Promise<string>|null = null;
  private resolve: Function|null = null;

  constructor() {
    this.reset();
  }

  reset() {
    this.greeting = new Promise<string>((resolve, reject) => {
      this.resolve = resolve;
    });
  }

在这里我们可以看到重新分配Promise必须触发更改检测,否则代码将无用。