我需要取消订阅 Ngrx Select吗

问题描述 投票:0回答:3

我有一个如下组件,其中有一个按钮在单击时调用

select_property
。问题是我不确定在每次点击时重新分配
$livevisitors
之前是否需要以任何方式取消订阅,不确定组件模板中的
$livevisitors | async
是否对我有用。

export class LiveComponent{

    livevisitors$: Observable<LiveVisitor[]>;
    selected_property_id: number = 0;

    constructor(
            private store: Store<AppState>
        ) {

        this.livevisitors$ = this.store.select(selectAllLiveVisitors);

    }

    select_property(id){
        this.selected_property_id = id;

        if (id == 0){
            this.livevisitors$ = this.store.select(selectAllLiveVisitors);
        } else {
            this.livevisitors$ = this.store.select(selectLiveVisitorsByPropertyId, {property_id: id});
        }
    }
angular ngrx ngrx-store
3个回答
6
投票

async管道为您订阅和取消订阅。您无需管理手动取消订阅。

来自官方文档

当组件被销毁时,异步管道会自动取消订阅以避免潜在的内存泄漏。


3
投票

但是,如果您订阅组件中的可观察对象,则会引入潜在的内存泄漏:

export class LiveComponent{

    livevisitors$: Observable<LiveVisitor[]>;
    selected_property_id: number = 0;

    constructor(
            private store: Store<AppState>
        ) {

    }

     ngOnInit() {
        //Potential memory leak
        this.store.select(selectAllLiveVisitors).subscribe(() = > {...})

     }

}

如果是这种情况,那么您需要在组件被销毁时取消订阅。一个优雅的解决方案是声明一个主题属性:

export class LiveComponent implements OnInit, OnDestroy {
    destroyed$: Subject<void> = new Subject<void>();
    livevisitors$: Observable<LiveVisitor[]>;
    selected_property_id: number = 0;

    constructor(
            private store: Store<AppState>
        ) {

    }

     ngOnInit() {
        // will unsubscribe when component is destroyed
        this.store.select(selectAllLiveVisitors)
           .pipe(takeUntil(this.destroyed$))
           .subscribe(() = > {...})

     }

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


0
投票

当我们在OnInit方法中订阅时,可能存在潜在的内存泄漏。示例:

export class RegisterComponent extends BaseComponent implements OnInit {
    loading = false;

    constructor(private store: Store) {}

    ngOnInit(): void {
        this.store.select(fromAuth.selectAuthLoading)
           .subscribe(loading => this.loading = loading);
    }

}

当我们使用异步管道时,我们是安全的。示例:

HTML:

@if (recipe$ | async; as recipe) {
    <div> {{recipe.name}} </div>
}

TS:

export class RecipeDetailComponent implements OnInit {
    recipe$: Observable<Recipe | null> = this.store.select(fromRecipes.selectRecipeDetails);

    constructor(private store: Store) {
    }

    ngOnInit(): void {
    }
}

为了扩展 Or Shalmayev 评论,我们实际上可以扩展我们正在订阅的组件。

TS基础.组件:

@Injectable()
export class BaseComponent implements OnDestroy {
    destroyed$: Subject<void> = new Subject<void>();

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

TS寄存器组件:

@Component({
selector: 'app-register',
standalone: true,
imports: [],
templateUrl: './register.component.html',
styleUrl: './register.component.scss'
})
export class RegisterComponent extends BaseComponent implements OnInit {
    loading = false;

    constructor(private store: Store) {
        super();
    }

    ngOnInit(): void {
        this.store.select(fromAuth.selectAuthLoading)
            .pipe(takeUntil(this.destroyed$))
            .subscribe(loading => this.loading = loading);
    }
}

总结一下: 我更喜欢使用异步管道,但也可以扩展组件并使我们的组件干净。

© www.soinside.com 2019 - 2024. All rights reserved.