behaviorsubject 从回调更新的订阅结果
behaviorsubject Result of subscribe updated from callback
我不明白为什么或如何从回调中更新值,虽然 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);
}
}
这是正在运行的 stackblitz:https://stackblitz.com/edit/angular-hdez5o
我的问题:正如上面的代码,它工作正常(我有我的香蕉)。但是,如果您注释掉 WORKS FINE
下面的 2 行并取消注释 DOES NOT WORK
下面的行,那么我只有黄色香蕉。
即使在组件的单独实例中,它也会是对 aha 对象的有趣引用吗?这怎么可能,我错过了什么?我必须复制 aha 才能工作吗?我很困惑。
这是因为这一行:
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>
我不明白为什么或如何从回调中更新值,虽然 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);
}
}
这是正在运行的 stackblitz:https://stackblitz.com/edit/angular-hdez5o
我的问题:正如上面的代码,它工作正常(我有我的香蕉)。但是,如果您注释掉 WORKS FINE
下面的 2 行并取消注释 DOES NOT WORK
下面的行,那么我只有黄色香蕉。
即使在组件的单独实例中,它也会是对 aha 对象的有趣引用吗?这怎么可能,我错过了什么?我必须复制 aha 才能工作吗?我很困惑。
这是因为这一行:
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>