angular - Angular Subject 多个不需要的订阅在组件之间进行对话
问题描述
我正在学习主题以及如何使用它在组件之间进行对话。
这是我的设置
消息总线.service.ts
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
@Injectable({
providedIn: 'root'
})
export class MessageBusService {
private subject: Subject<any>;
constructor() {
this.subject = new Subject<any>();
}
sendMessage(type: string, data?: any) {
this.subject.next({ type, data });
}
clearMessage() {
this.subject.next();
}
getMessage(): Observable<any> {
return this.subject.asObservable();
}
}
然后我有一个type.component.ts我目前仅用于单击 UI 中的按钮并打开一个模式。
constructor(
private contentTypeService: ContentTypeService,
private messageBusService: MessageBusService,
private dialog: MatDialog,
) {
this.contentTypes = new MatTableDataSource([]);
this.initSubscriptions();
this.contentTypes.sort = this.sort;
}
ngOnInit(): void {
this.loadContentTypes();
}
sortData() {
this.contentTypes.sort = this.sort;
}
private initSubscriptions() {
this.subscriptions = [
this.messageBusService
.getMessage()
.subscribe(message => {
if (!message) return;
if (message.type == SEARCH_VALUE_CHANGED) {
this.contentTypes.filter = message.data.trim().toLowerCase();
} else if (message.type == PAGE_HEADER_CREATE_CLICKED) {
this.openCreateModal();
}
})
]
}
openCreateModal() {
const dialogRef = this.dialog.open(ContentTypeModalComponent, {
data: {
title: 'Content Type',
},
width: '550px',
// height: '530px',
});
dialogRef.afterClosed().subscribe(result => {
console.log(`Dialog result: ${result}`);
});
}
我的 Modal 由一个基本的可重用 modal 组成,它只定义页眉和页脚,并通过 . 因此,为了使事情更短,我将只在此处添加组件特定的模式,该模式会报告回我的 type.component.ts,这是我想要然后对模式中的结果执行某些操作的地方。
conten_type-modal.component.ts
import { Component, OnInit, Inject, Input } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import * as _ from 'lodash';
import { FormGroup, FormArray, FormBuilder, Validators } from '@angular/forms';
import { MessageBusService } from '../../../shared/services/message-bus.service';
import { MODAL_CREATE_CLICKED, MODAL_CANCEL_CLICKED, MODAL_CLOSE_CLICKED } from '../../../shared/constants/modal-events';
import { Subscription } from 'rxjs';
@Component({
selector: 'content_type-modal',
templateUrl: './content_type-modal.component.html',
styleUrls: ['./content_type-modal.component.scss']
})
export class ContentTypeModalComponent implements OnInit {
form: FormGroup;
subscriptions: Subscription[];//Use array if multiple subs
constructor(
@Inject(MAT_DIALOG_DATA) public data,
private messageBusService: MessageBusService,
public dialogRef: MatDialogRef<ContentTypeModalComponent>,
private fb: FormBuilder,
) {
this.form = this.fb.group({
name: [null, Validators.compose([Validators.required, Validators.maxLength(40)])],
weightToVolumeRatio: [null, Validators.min(0)],
});
this.subscriptions = [
this.messageBusService
.getMessage()
.subscribe(message => {
if (!message) return;
console.log("got ", message);
if (message.type === MODAL_CREATE_CLICKED) {
this.save();
} else if (message.type === MODAL_CLOSE_CLICKED) {
this.closeModal();
}
})
]
}
ngOnInit() {
}
save() {
console.log(this.form.value);
this.dialogRef.close(this.form.value);
}
ngOnDestroy(): void {
// unsubscribe to any subscriptions ensure no memory leaks
// this.subscriptions.forEach(subscription => subscription.unsubscribe());
}
closeModal() {
this.dialogRef.close();
}
}
现在我意识到拥有一个消息总线可能不是一个好主意,让所有东西都在不加选择的情况下运行,因此您订阅的数量超过了您可能关心的数量,但我稍后会拆分它。
我的问题是,当我单击打开模式时,说我取消(中止)并因此关闭模式,然后我再次打开它,输入一些信息,然后按创建(保存)然后按我的主要组件 type.component.ts使用消息类型 MODAL_CREATE_CLICKED 两次(或打开和关闭对话框的 x 次)获取订阅回调。
if (message.type === MODAL_CREATE_CLICKED) {
this.save();
}
有人可以解释一下为什么会这样吗?我很困惑……
解决方案
这里不是缺少代码吗?
你在哪里做this.messageBusService.sendMessage(type: string, data?: any)
这个,任何用主题初始化的观察者都应该被调用。
如果这是整个代码。您可能正在获得初始主题值。
您不断收到消息增加的原因是因为您没有关闭/结束观察者和主题之间的连接。
例子:
modal_instance_1 这会初始化订阅。
您关闭模式,但订阅仍在内存中。
modal_instance_2 这会初始化另一个订阅。
但您仍有第一个订阅可用。
使用 rxjs observables 等时的经验法则是决定您希望该订阅可用多长时间。
示例:一旦主题发出第一个值,关闭连接。
this.messageBusService.getMessage()
.pipe(take(1)) // can be x amount of times.
.subscribe(message => {
...
})
一旦组件被销毁,关闭连接。
private _destroy$: Subject<any> = new Subject()
constructor() {}
...
this.messageBusService.getMessage()
.pipe(takeUntil(this._destroy$) // can be x amount of times.
.subscribe(message => {
...
})
...
ngOnDestroy() {
this._destroy$.next()
this._destroy$.complete()
}
希望这会有所帮助:)
推荐阅读
- amazon-web-services - 如何创建仅允许在同一 CloudFormation 堆栈中创建的资源承担 IAM 角色的条件?
- node.js - 在运行时实例化一个知道文件路径的类
- r - htmltab 找不到使用数字或字符向量作为“哪个”参数的表
- android-kernel - 致命错误:fw_data_5517.i:没有这样的文件或目录#include“fw_data_5517.i”
- c# - 使用 Microsoft Graph 从 Office 365 邮箱中获取退回的电子邮件
- javascript - 如何仅从一个脚本运行所有脚本?(带有 React.js 的 HTML)
- javascript - 如何使用快递服务目录?
- javascript - 如何使用 HTML 画布裁剪图像并调整其大小而不使其模糊?
- java - 为什么浮点除法会返回整数结果(Java/Android)
- spring-boot - Springfox:如何手动将 api 路径添加到 swagger-ui?