поведенческие темы Результат подписки обновлен от обратного вызова - PullRequest
1 голос
/ 13 апреля 2019

Я не могу понять, почему или как обновляются значения из обратного вызова, хотя 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

Моя проблема: так как код выше, он работает нормально (у меня есть свои бананы). Однако, если вы закомментируете 2 строки ниже WORKS FINE и раскомментируете строку ниже DOES NOT WORK, тогда у меня только желтые бананы. Может ли это быть забавная ссылка на объект aha даже в отдельных экземплярах компонента? Как это возможно и чего мне не хватает? Нужно ли делать копию ага, чтобы он работал? Я совершенно сбит с толку.

1 Ответ

0 голосов
/ 13 апреля 2019

Причина этого заключается в следующей строке:

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

Вы переназначаете свойство объекта, испускаемого объектом BehaviorSubject.Он излучается три раза (один раз для каждого приложения, другой подписывается на него).Это означает, что во второй раз 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...