Ангуляр 4 отписки вызывает ошибку при навигации - PullRequest
0 голосов
/ 20 октября 2018

Я недавно научился избегать утечки памяти, мне нужно отписаться в моих компонентах.Для этого я реализую OnDestroy, но это вызвало проблему при навигации.

Ошибка ОШИБКИ: Uncaught (в обещании): TypeError: Невозможно прочитать свойство «отписаться» от неопределенного TypeError: Невозможно прочитать свойство'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...
            }
        );
    }

}

1 Ответ

0 голосов
/ 20 октября 2018

Здесь этот должен работать для вас.Я объединил поток параметров маршрута и поток getProperty, используя concatMap и функцию проекции.Вы можете прочитать больше об этом в rxjs docs: rxjs concatMap

Я также использую takeUntil, который отписывается от потока, в который он направляется, когда другой поток излучает. rxjs takeUntil

Таким образом, когда componentDestroyed$ издает наблюдаемый, потому что takeUntil принял его в качестве параметра, takeUntil затем откажется от потоков this._route.params и this._propertyService.getProperty.

Я также добавил takeUntil к onCreate методу, так как вы также подписываетесь там.

takeUntil - это альтернатива отслеживанию всех ваших Subuscription и отписке от них вручную.в ngOnDestroytakeUntil мы достигаем того же, но не должны загромождать компонент свойствами подписки.

Вы можете сделать это на один шаг вверх и получить базовый класс, от которого наследуются все ваши классы компонента -> тогда вам не нужно хранить 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();
    }
}
...