[英]Angular 2 - FormGroup ValueChanges Unsubscribe
我有一个带有 ValueChanges 事件的 FormGroup,当用户从组件的路由移动到另一个组件然后他们返回到该组件时,该事件没有从内存中释放。
这意味着如果用户 5 次离开组件然后返回组件,onFormChange 方法会触发 5 次,但其中只有 1 次调用是针对当前组件的。
我认为问题在于我需要取消订阅 NgDestroy 事件中的 valueChanges 事件,但 valueChanges 事件中没有可用的取消订阅方法。
我确定我必须取消订阅或释放内存,但我不确定是什么。
import * as _ from 'lodash';
import {Observable} from 'rxjs/Rx';
import {Component, Input, Output, EventEmitter, OnInit, OnDestroy} from '@angular/core';
import {FormGroup} from '@angular/forms';
import {formConfig} from './toolbar.form-config';
import {JobToolbarVm} from '../view-model/job-toolbar.vm';
import {BroadcastService} from '../../../services/broadcast/broadcast.service';
@Component({
selector: 'wk-job-toolbar',
template: require('./toolbar.html'),
})
export class JobToolbarComponent implements OnInit, OnDestroy {
protected form: FormGroup;
@Input()
toolbar: JobToolbarVm;
@Output()
toolbarChanged = new EventEmitter<JobToolbarVm>();
@Output()
refresh = new EventEmitter<string>();
constructor(private broadcast: BroadcastService) {
}
ngOnInit() {
this.form = formConfig;
this.form.setValue(this.toolbar, {onlySelf: true});
// This ALWAYS RUNS when the form loads, ie. on the job route
console.log('FORM VALUE');
console.log(JSON.stringify(this.form.value, null, 2));
this.form.valueChanges
.debounceTime(2000)
.subscribe(
this.onFormChange.bind(this)
);
}
ngOnDestroy() {
//this.form.valueChanges.unsubscribe();
//this.onChanges.unsubscribe();
//this.toolbarChanged.unsubscribe();
//this.form = null;
}
onFormChange(data: any) {
// This runs whenever I go to a different route and then come back to this route
// There is also a memory leak, because this method fires multiple times based on how
// often I navigate away and come back to this route.
// e.g. Navigate away and then back 5 times, then I see this log statement 5 times
console.log('FORM VALUE2 - THIS KEEPS FIRING FOR EACH INSTANCE OF MY COMPOMENT');
console.log(JSON.stringify(this.form.value, null, 2));
JobToolbarVm.fromJsonIntoInstance(data, this.toolbar);
this.onChanges('data-changed');
}
onChanges($event: any) {
console.log('onChanges: ' + $event);
// console.log(this.toolbar);
// Send the toolbar object back out to the parent
this.toolbarChanged.emit(this.toolbar);
// Broadcast an event that will be listened to by the list component so that it knows when to refresh the list
this.broadcast.broadcast('job-admin-toolbar-changed', this.toolbar);
}
}
subscribe()
调用返回一个Subscription
,这是您用来取消订阅的:
class JobToolbarComponent
private subscr:Subscription;
ngOnInit() {
...
this.subscr = this.form.valueChanges ...
...
}
ngOnDestroy() {
this.subscr.unsubscribe();
}
}
我创建了以下功能
export function AutoUnsubscribe(exclude = []) {
return function (constructor) {
const original = constructor.prototype.ngOnDestroy;
constructor.prototype.ngOnDestroy = function () {
for (let prop in this) {
const property = this[prop];
if (!exclude.includes(prop)) {
if (property && (typeof property.unsubscribe === "function")) {
property.unsubscribe();
}
}
}
original && typeof original === 'function' && original.apply(this, arguments);
};
}
}
实际上,您可以使用它来自动取消订阅所有观察者,但您必须将它们存储在公共属性中,以便该函数可以拦截它并对其调用取消订阅。 您如何使用它如下所述:-
@AutoUnsubscribe()
@Component({
selector: 'account-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {
public submitWatcher: Subscription;
submit() {
this.submitWatcher = this.authService.login(this.loginForm.getRawValue())
.subscribe(res => {
if (this.returnUrl) {
this.router.navigate([this.returnUrl]);
}
else {
this.router.navigate(['/special']);
}
}, (error) => {
alert(JSON.stringify(error.data));
});
}
}
有关如何使用装饰器的更多信息,请阅读这个博客,这是我从中获得这个想法的地方,它非常酷
您可以执行以下操作:
// private variable to hold all your subscriptions for the component
private subscriptions: Subscription[] = [];
// when you subscribe to an observable,
// you can push all subscription this.subscriptions
this.subscriptions.push(
this.form.valueChanges.pipe(
.debounceTime(2000))
.subscribe(val => this.onFormChange.bind(this)),
this.observe2$.subscribe(val => this.somemethod(val))
);
// in ngondestroy
ngOnDestroy(): void {
if (this.subscriptions && this.subscriptions.length > 0) {
this.subscriptions.forEach(s => s.unsubscribe());
}
}
我不确定这是否是一个好主意,但这很容易实现,并且适用于我的学校项目。
var sub = this.items.subscribe(snapshots => {
console.log(snapshots);
sub.unsubscribe();
});
来源: https ://github.com/angular/angularfire2/issues/377
将订阅组合在一起的最简单方法是使用 add 方法:subscription.add( anotherSubscription ) 所以现在您只需取消订阅一个订阅。
您可以从官方文档中找到以下示例: https ://rxjs.dev/guide/subscription
import { interval } from 'rxjs';
const observable1 = interval(400);
const observable2 = interval(300);
const subscription = observable1.subscribe(x => console.log('first: ' + x));
const childSubscription = observable2.subscribe(x => console.log('second: ' + x));
subscription.add(childSubscription);
setTimeout(() => {
// Unsubscribes BOTH subscription and childSubscription
subscription.unsubscribe();
}, 1000);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.