【问题标题】:Angular2/4 unsubscribe observable in a component which never be destroyedAngular2/4 在一个永远不会被销毁的组件中取消订阅 observable
【发布时间】:2018-05-06 22:36:49
【问题描述】:

我是 Angular4 的新手。很抱歉这个基本问题和我糟糕的英语。我会尽力描述我的问题。

我现在正在开发一个使用可观察服务来共享消息的网站。

但我遇到了一个问题, 这是我的example file structure。和working Plunker

我的“标题组件”收到了来自“用户组件”的消息。

标题组件:

import { Component, OnInit, OnDestroy} from '@angular/core';
import { Subscription } from 'rxjs/subscription';
import { SharedService } from "./sharedService";

@Component({
  selector: 'shared-header',
  template: `<div class="my-header">
              <span>This is header </span>
              <span class="right-align">Recieve Data:{{received}}</span>  
            </div>`,
})

export class HeaderComponent implements OnInit, OnDestroy{

  private subscription: Subscription;
  private received = "none";

  constructor(private sharedService : SharedService) {}

  ngOnInit(){
    this.subscription = this.sharedService.shareAction$.subscribe(result => {
      if(result){
        this.received = result;
      } 
    };
  }

  ngOnDestory(){
    this.subscription.unsubscribe();
  }
}

用户组件:

import { Component, OnInit, OnDestroy} from '@angular/core';
import { Subscription } from 'rxjs/subscription';
import { SharedService } from "./sharedService";

@Component({
  selector: 'shared-header',
  template: `<div class="my-header">
              <span>This is header </span>
              <span class="right-align">Recieve Data:{{received}}</span>  
            </div>`,
})

export class HeaderComponent implements OnInit, OnDestroy{

  private subscription: Subscription;
  private received = "none";

  constructor(private sharedService : SharedService) {}

  ngOnInit(){
    this.subscription = this.sharedService.shareAction$.subscribe(result => {
      if(result){
        this.received = result;
      } 
    };
  }

  ngOnDestory(){
    this.subscription.unsubscribe();
  }
}

并且“Widget Component”收到来自“Product Component”的消息。

小部件组件:

import { Component, OnInit, OnDestroy} from '@angular/core';
import { Subscription } from 'rxjs/subscription';
import { SharedService } from "./sharedService";

@Component({
  selector: 'widget',
  template: `<div>---Widget----</div>
             <div>=={{productName}}==</div>`,
})

export class WidgetComponent implements OnInit, OnDestroy{

  private productName = "none";
  private subscription: Subscription;

  constructor(private sharedService : SharedService) {}

  ngOnInit(){
    this.subscription = this.sharedService.shareAction$.subscribe(result => {
      if(result){
        this.productName = result;
      } 
    };
  }
  ngOnDestory(){
    this.subscription.unsubscribe();
  }
}

产品组件:

import { Component, OnInit, OnDestroy} from '@angular/core';
import { SharedService } from "./sharedService";

@Component({
  template: `<h4>This is ProductPage</h4>
             <widget></widget>`,
})

export class ProductComponent implements OnInit, OnDestroy{

  constructor(private sharedService : SharedService) {}

  ngOnInit(){
    this.sharedService.publishData('NIKE');
  }
}

我创建了一个 sharedService 来处理可观察的服务。 共享服务:

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Subscription } from 'rxjs/subscription';

@Injectable()
export class SharedService {

  private shareAction = new BehaviorSubject<any>(null);
  shareAction$ = this.shareAction.asObservable()
  sharedObject: object = {};

  constructor() {}

  publishData(data) {
    console.log('publish------------------------------');
    this.shareAction.next(data);
  }
}

所以当点击“用户页面”时,标题右侧的信息将显示“用户页面”。 当点击“产品页面”时,小部件下方的信息将显示“NIKE”。但与此同时,标题信息也更改为“NIKE”,我不希望它发生。

我知道当组件销毁时我应该取消订阅,但是在这种情况下,Header 永远不会被销毁。所以也许......我应该在“用户组件”销毁时取消订阅,并在“用户组件”初始化时再次订阅,但我不知道该怎么做,或者这个想法很糟糕。

请给我一些指导,任何意见都会有所帮助。 非常感谢。

【问题讨论】:

  • 为什么不添加上述组件的相关部分?
  • 感谢您的意见,我更新了我的问题。

标签: angular rxjs observable unsubscribe


【解决方案1】:

我认为问题在于您使用单个 shareAction$ 来做太多事情。为什么不为标题信息创建一个主题,为小部件创建另一个主题?

另外,shareAction$ 过于宽泛:尝试给它一个更具体的名称,例如 headerTitle$currentProduct$

import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Subscription } from 'rxjs/subscription';

@Injectable()
export class SharedService {

    private headerTitle = new BehaviorSubject<string>(null);
    headerTitle$ = this.headerTitle.asObservable();

    private currentProduct = new BehaviorSubject<any>(null);
    currentProduct$ = this.currentProduct.asObservable();

    constructor() {}

    setHeaderTitle(title:string):void {
        this.headerTitle.next(title);
    }
    setCurrentProduct(product:any):void {
        this.currentProduct.next(product);
    }
}

这样,Header 组件和 Widget 组件都不需要知道何时订阅/取消订阅:它们只是在创建时订阅,在销毁时取消订阅。

另外,请考虑避免将 any 作为类型:当您的应用程序足够大时,它将为您节省很多问题,因为如果有一些更改会导致类型不匹配,编译器会告诉您有问题。

您是否需要通过服务全局共享CurrentProduct?如果你只在 Product 组件中使用它 - Widget 组件可能通过组件参数传递它就足够了。

【讨论】:

  • 非常感谢,你拯救了我的一天!是的,我需要将当前产品全局共享给其他组件,我只是简化了我的代码。并感谢您的额外建议。真的很有帮助,非常感谢!
【解决方案2】:

使用 Angular 2+ 内置机制 (| async),它会自动取消订阅。

some.component.ts:

this.heroes = this.heroService.getHeroes();

一些.component.html:

<li *ngFor="let hero of heroes | async" (click)="selectedHero=hero">
    <span class="badge">{{hero.id}}</span> {{hero.name}}
</li>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-08-29
    • 2018-02-13
    • 2016-12-06
    • 1970-01-01
    • 2019-07-27
    • 2021-02-25
    • 2013-04-16
    • 2019-07-18
    相关资源
    最近更新 更多