Angular 4退订导航时会导致错误

时间:2018-10-19 22:11:31

标签: angular rxjs angular4-router

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

  

ERROR错误:未捕获(承诺):TypeError:无法读取未定义的属性“ unsubscribe”   TypeError:无法读取未定义的属性“取消订阅”

如果我不取消订阅,导航将成功完成。

我的印象是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...
            }
        );
    }

}

1 个答案:

答案 0 :(得分:1)

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

我还使用takeUntil,当其他流发出时,它从管道中取消订阅。 rxjs takeUntil

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

我还向takeUntil方法中添加了onCreate,因为您也在那里订阅了。

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

您可以更进一步,并拥有所有组件类都继承自->的基类,那么您不必在每个组件中保留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();
    }
}