在 angular 中使用 Subjects/event 发射器进行跨组件通信时出现奇怪的行为?
Weird behavior while using Subjects/event emitters in services for cross component communication in angular?
我想了解 observable、subjects 和 behavior subject 是如何工作的(读了很多文章,看了很多视频,但我还是不清楚,因为我没能解释这种行为)所以我创建了这个简单的例子,并得到了意想不到的行为。
我有两个组件,一个 父组件 和一个 子组件 。
父组件显示一个包含照片名称的列表,并带有显示详细信息的按钮。单击此按钮后,它将带我们进入子组件,我希望在其中显示单张照片以及详细信息。所以,这就是想法。
我使用了一个有主题的服务。现在,每当单击父组件中的按钮时,我都会从主题中发出一个值。我想在我的子组件中捕获这个值,所以我订阅它。
有一个奇怪的行为--
对于第一次点击,我没有在我的子组件中看到任何数据。
第二次单击子组件中的单个值。
第三次单击子组件中的两个值,
等等....
这是我的组件--
parent.component.ts
export class ParentComponent implements OnInit {
photoList = [
{
albumId: 1,
id: 1,
title: "accusamus beatae ad facilis cum similique qui sunt",
url: "https://via.placeholder.com/600/92c952",
thumbnailUrl: "https://via.placeholder.com/150/92c952",
},
{
albumId: 1,
id: 2,
title: "reprehenderit est deserunt velit ipsam",
url: "https://via.placeholder.com/600/771796",
thumbnailUrl: "https://via.placeholder.com/150/771796",
},
{
albumId: 1,
id: 3,
title: "officia porro iure quia iusto qui ipsa ut modi",
url: "https://via.placeholder.com/600/24f355",
thumbnailUrl: "https://via.placeholder.com/150/24f355",
},
];
constructor(private _talkService: TalkService, private router: Router) {}
ngOnInit() {}
displayName(id, url, thumbnailUrl) {
console.log({ id, url, thumbnailUrl });
//this._talkService.talk.emit({ url, thumbnailUrl });
this._talkService.talk.next({ id, url, thumbnailUrl });
this.router.navigate(["/photo"]);
}
}
child.component.ts
export class ChildComponent implements OnInit {
constructor(private _talkService: TalkService) {}
ngOnInit() {
console.log("child component created");
this._talkService.talk.subscribe((data) => {
console.log(data);
});
}
}
talk.service.ts
@Injectable({
providedIn: "root",
})
export class TalkService {
// talk = new EventEmitter();
talk = new Subject();
constructor() {}
}
输出控制台日志
这三个我都用过--
事件发射器-->与描述的行为相同
受试者-->与描述的行为相同
Behavior Subjects--> 我也得到了第一个值(因为它帮助我们得到之前发出的值,我理解那部分)。也欢迎在这里详细解释。
我原以为每次点击都有一个值,但事实并非如此。有人可以向我解释这种行为吗?这一定是 observable 工作的方式,我无法得到它。
这是我的 github 仓库的 link--
听起来像是典型的内存泄漏。每次您订阅 talkService.talk
时,您都在创建一个只有在取消订阅后才会被清理的订阅。因此,即使当您返回到父组件时,子组件看起来像是被销毁了,订阅仍然存在,并且每次 talk
主题发出新值时都会执行控制台日志。当 Child 组件被销毁时,您应该取消订阅。确保取消订阅的一种简单方法是使用 html 模板中的 async
管道。
child.component.ts
export class ChildComponent implements OnInit {
data$: Observable<any> = this.talkService.talk;
constructor(private talkService: TalkService) {}
}
child.component.html
<pre>{{ data$ | async }}</pre>
此外,您可以切换回使用 BehaviorSubject
,因为子组件将在从父组件发出值后订阅 talk
。
我想了解 observable、subjects 和 behavior subject 是如何工作的(读了很多文章,看了很多视频,但我还是不清楚,因为我没能解释这种行为)所以我创建了这个简单的例子,并得到了意想不到的行为。 我有两个组件,一个 父组件 和一个 子组件 。
父组件显示一个包含照片名称的列表,并带有显示详细信息的按钮。单击此按钮后,它将带我们进入子组件,我希望在其中显示单张照片以及详细信息。所以,这就是想法。
我使用了一个有主题的服务。现在,每当单击父组件中的按钮时,我都会从主题中发出一个值。我想在我的子组件中捕获这个值,所以我订阅它。
有一个奇怪的行为-- 对于第一次点击,我没有在我的子组件中看到任何数据。 第二次单击子组件中的单个值。 第三次单击子组件中的两个值, 等等....
这是我的组件--
parent.component.ts
export class ParentComponent implements OnInit {
photoList = [
{
albumId: 1,
id: 1,
title: "accusamus beatae ad facilis cum similique qui sunt",
url: "https://via.placeholder.com/600/92c952",
thumbnailUrl: "https://via.placeholder.com/150/92c952",
},
{
albumId: 1,
id: 2,
title: "reprehenderit est deserunt velit ipsam",
url: "https://via.placeholder.com/600/771796",
thumbnailUrl: "https://via.placeholder.com/150/771796",
},
{
albumId: 1,
id: 3,
title: "officia porro iure quia iusto qui ipsa ut modi",
url: "https://via.placeholder.com/600/24f355",
thumbnailUrl: "https://via.placeholder.com/150/24f355",
},
];
constructor(private _talkService: TalkService, private router: Router) {}
ngOnInit() {}
displayName(id, url, thumbnailUrl) {
console.log({ id, url, thumbnailUrl });
//this._talkService.talk.emit({ url, thumbnailUrl });
this._talkService.talk.next({ id, url, thumbnailUrl });
this.router.navigate(["/photo"]);
}
}
child.component.ts
export class ChildComponent implements OnInit {
constructor(private _talkService: TalkService) {}
ngOnInit() {
console.log("child component created");
this._talkService.talk.subscribe((data) => {
console.log(data);
});
}
}
talk.service.ts
@Injectable({
providedIn: "root",
})
export class TalkService {
// talk = new EventEmitter();
talk = new Subject();
constructor() {}
}
输出控制台日志
这三个我都用过--
事件发射器-->与描述的行为相同 受试者-->与描述的行为相同 Behavior Subjects--> 我也得到了第一个值(因为它帮助我们得到之前发出的值,我理解那部分)。也欢迎在这里详细解释。
我原以为每次点击都有一个值,但事实并非如此。有人可以向我解释这种行为吗?这一定是 observable 工作的方式,我无法得到它。
这是我的 github 仓库的 link--
听起来像是典型的内存泄漏。每次您订阅 talkService.talk
时,您都在创建一个只有在取消订阅后才会被清理的订阅。因此,即使当您返回到父组件时,子组件看起来像是被销毁了,订阅仍然存在,并且每次 talk
主题发出新值时都会执行控制台日志。当 Child 组件被销毁时,您应该取消订阅。确保取消订阅的一种简单方法是使用 html 模板中的 async
管道。
child.component.ts
export class ChildComponent implements OnInit {
data$: Observable<any> = this.talkService.talk;
constructor(private talkService: TalkService) {}
}
child.component.html
<pre>{{ data$ | async }}</pre>
此外,您可以切换回使用 BehaviorSubject
,因为子组件将在从父组件发出值后订阅 talk
。