Angular 4 取消订阅导致导航时出错

Angular 4 unsubscribe causes an error when navigating

我最近学会了避免内存泄漏,我需要取消订阅我的组件。为此,我实施了 OnDestroy 但这在导航时引起了问题。

ERROR Error: Uncaught (in promise): TypeError: Cannot read property 'unsubscribe' of undefined TypeError: Cannot read property 'unsubscribe' of undefined

如果我不退订导航成功完成。

我的印象是 ngOnDestroy 只有在其他所有事情都完成后才会发生,显然事实并非如此。

我显然做错了什么,但我无法弄清楚离开页面时如何取消订阅?

export class PropertyFormMapperComponent implements OnInit, OnDestroy {
    private _routeSubscription: any;
    private _getPropertySubscription: any;

    constructor(
        private _route: ActivatedRoute,
        private _propertyFormFileService: PropertyFormFileService,
        private _router: Router
    ) { }

    ngOnInit(): void {
        this._routeSubscription = this._route.params.subscribe(params => {
            this._id = params['id'];
            this._getPropertySubscription = this._propertyService.getProperty(this._id).subscribe(property => {
                ...do stuff...
            });
        });
    }

    ngOnDestroy(): void {
        this._routeSubscription.unsubscribe();
        this._getPropertySubscription.unsubscribe();
    }

    private onCreate(event: any): void {    
        this._propertyService.postProperty(property, 1).subscribe(
            response => {
                ...do stuff...
                this._router.navigate(['home']);
            },
            error => {
                ...other stuff...
            }
        );
    }

}

在这里,这个应该适合你。我使用 concatMap 和投影函数组合了路由参数流和 getProperty 流。您可以在 rxjs 文档中阅读更多相关信息:rxjs concatMap

我还使用 takeUntil 取消订阅其他流发出时通过管道传输到的流。 rxjs takeUntil

因此,当 componentDestroyed$ observable 发出时,因为 takeUntil 将其作为参数,takeUntil 将取消订阅 this._route.paramsthis._propertyService.getProperty 流。

我还添加了 takeUntilonCreate 方法,因为你也在那里订阅。

takeUntil 是跟踪所有 Subuscription 并在 ngOnDestroy 中手动取消订阅的替代方法。使用 takeUntil 我们实现了相同的目的,但不必使用订阅属性使组件混乱。

您可以更进一步,拥有一个基础 class,您的所有组件 class 都继承自 --> 然后您不必保留 componentDestroyed$每个组件也可以跳过 ngOnDestroy() 部分:

export abstract class BaseComponent implements OnDestroy {
    protected componentDestroyed$: Subject<void> = new Subject<void>();

    ngOnDestroy() {
        this.componentDestroyed$.next();
        this.componentDestroyed$.complete();
    }
}

您的组件现在将从 BaseComponent:

继承

export class PropertyFormMapperComponent extends BaseComponent implements OnInit, OnDestroy

您的代码已修复:

import {Subscription} from 'rxjs';
import {tap, map, concatMap, takeUntil} from 'rxjs/operators';

export class PropertyFormMapperComponent implements OnInit, OnDestroy {
    componentDestroyed$: Subject<void> = new Subject<void>();

    constructor(
        private _route: ActivatedRoute,
        private _propertyFormFileService: PropertyFormFileService,
        private _router: Router
    ) { }

    ngOnInit() {
        this._route.params
            .pipe(
                map(params => params['id']),
                tap(id => this._id = id),
                concatMap(id => this._propertyService.getProperty(id))
                takeUntil(this.componentDestroyed$),
                tap(property => {
                   ...do stuff...
                   ... side effects are handled in tap functions     
                })
            )
            .subscribe();        
    }

    private onCreate(event) {    
        this._propertyService.postProperty(property, 1)
            .pipe(
                takeUntil(this.componentDestroyed$)
            )
            .subscribe(
                response => {
                    ...do stuff...
                    this._router.navigate(['home']);
                },
                error => {
                    ...other stuff...
                }
            );
    }

    ngOnDestroy() {
        this.componentDestroyed$.next();
        this.componentDestroyed$.complete();
    }
}