behaviorsubject从回调更新订阅的结果

时间:2019-04-13 01:35:19

标签: typescript callback rxjs angular7 subscribe

我无法弄清楚为什么或如何从回调中更新值,但是虽然BehaviorSubject只能通过next()进行更新...但是也许是因为睡眠不足?

这是代码:

import { Component, OnInit, Input, Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  private testSource = new BehaviorSubject([]);

  testCurrent = this.testSource.asObservable();

  constructor() { }
  changeTest(test: any) {
    this.testSource.next(test);
  }
}

@Component({
  selector: 'app-another',
  template: `<div *ngFor="let nope of whatEver">{{nope.bananas}}</div>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class AnotherComponent {
  @Input() rando: string;
  constructor(private data: DataService) { }
  whatEver: [];
  ngOnInit() {
    this.data.testCurrent.subscribe(aha => {
      // WORKS FINE:
      const omg = JSON.parse(JSON.stringify(aha))
      this.whatEver = omg.reduce((accu, a) => {
      // DOES NOT WORK (changes the variable aha -> WHY?):
      //this.whatEver = aha.reduce((accu, a) => {
        a.bananas = a.bananas.filter(b => b === this.rando || b === "yellow");
        accu.push(a);
        return accu;
      }, []);
    });
  }
}

@Component({
  selector: 'my-app',
  template: `<app-another *ngFor="let why of maybe" [rando]="why"></app-another>`,
  styles: [`h1 { font-family: Lato; }`]
})
export class AppComponent implements OnInit  {
  idontknow = [
    {
      id: "come-on",
      bananas: ["yellow", "big", "tasty"]
    }
  ];
  maybe = ["yellow", "big", "tasty"];
  constructor(private data: DataService) { }
  ngOnInit() {
    this.data.changeTest(this.idontknow);
  }
}

这是有效的堆叠闪电战:https://stackblitz.com/edit/angular-hdez5o

我的问题:如上面的代码所示,它工作正常(我有香蕉)。但是,如果您注释掉WORKS FINE下面的两行并取消注释DOES NOT WORK下面的行,那么我只有黄色香蕉。 即使在组件的单​​独实例中,对aha对象的引用也会很有趣吗?那怎么可能?我想念什么?我必须复制一份AHA才能正常工作吗?我很困惑。

1 个答案:

答案 0 :(得分:0)

原因是因为以下这一行:

a.bananas = a.bananas.filter(...);

您正在重新分配BehaviorSubject发出的对象的属性。它发出了3次(每个应用(订阅该应用的另一个)一次)。这意味着第二次a.bananas将是从先前订阅中过滤的内容。

要解决此问题,请不要重新分配对象属性。创建具有相应属性的新对象。例如:https://stackblitz.com/edit/angular-tumnrd?file=src/app/app.component.ts

const bananas = a.bananas.filter(...);
accu.push({ ...a, bananas });

您也不需要(或一定要)创建订阅。您将不得不退订(可能在ngOnDestroy中),否则可能会发生内存泄漏。我建议使用异步管道来处理此问题:https://stackblitz.com/edit/angular-tumnrd?file=src/app/app.component.ts

this.whatEver = this.data.testCurrent.pipe(
  map(aha =>
    aha.map(({ bananas }) => ({
      bananas: bananas.filter(b => b === this.rando || b === 'yellow')
    }))
  )
);
// ... in template ...
<div *ngFor="let nope of whatEver | async">{{nope.bananas}}</div>