【问题标题】:Angular 8 - subscribe to one service from two different componentsAngular 8 - 从两个不同的组件订阅一项服务
【发布时间】:2020-06-21 02:18:20
【问题描述】:

我有一个 Angular 服务和两个不同的使用该服务的不相关组件:

服务代码:

const url = 'ws://localhost:8080

@Injectable({
   provideIn: 'root',
})

export class MyService{

  public subject: Subject<Status>;

  constructor(wsService: WebSocketService){
    this.subject = <Subject<Status>>wsService.connect(url).map(
       (response: MessageEvent): Status => {
          let data = JSON.parse(response.data);
          return data;
        }
    );
  }

  getObs(){
    return this.subject.asObservable();
  }

  sendMsg(msg){
    this.subject.next(msg);
  }

}

组件 1:

@Component

.. some irrelevant code ..

constructor(private service: MyService){
  this.service.getObs().subscribe( data => 
    console.log('comp1');
  );

  console.log('comp1 - after subscribe');
}

.. some irrelevant code ..

组件 2:

@Component

.. some irrelevant code ..

constructor(private service: MyService){
  this.service.getObs().subscribe( data => 
    console.log('comp2');
  );

  console.log('comp2 - after subscribe');
}

.. some irrelevant code ..

我在控制台中得到以下输出:

comp1

comp1 - 订阅后

comp2 - 订阅后

我认为我应该得到的输出:

comp1

comp1 - 订阅后

comp2

comp2 - 订阅后

谁能解释一下问题出在哪里?

注意:我将服务添加到模块提供程序并得到相同的结果。

谢谢。

这里是 webSocketService 的代码:https://github.com/elliotforbes/ng-chat/blob/master/src/app/common/services/websocket.service.ts

【问题讨论】:

标签: angular service components observable subject


【解决方案1】:

您应该控制自己的主题,而不是捎带WebSocketService.connect 并假设您将获得所需的行为。

从您发布的WebSocketService 源代码的链接中,我们看到它是一个普通主题。 ReplaySubject 提供您想要的功能 - 在订阅时发出一个值(假设存在)。

您应该声明一个本地ReplaySubject,这是您的组件将订阅的内容。然后,您将订阅您的WebSocketService。来自WebSocketService 的任何响应都将映射到一个状态,然后发送到您的本地主题。

const url = 'ws://localhost:8080

@Injectable({
   provideIn: 'root',
})

export class MyService{

  // Declare local ReplaySubject that emits the last value upon subscription
  private subject: Subject<Status> = new ReplaySubject<Status>(1);

  constructor(wsService: WebSocketService) {
    // Subscribe to the web socket service.
    // Subscribing in constructors is fairly bad practice, 
    // although you can get away with it in singleton services
    wsService.connect(url).pipe(
      // map responses to statuses
      map((response: MessageEvent): Status => {
        let data = JSON.parse(response.data);
        return data;
      })
    ).subscribe((status: Status) => {
      // send the status to all subscribers
      this.subject.next(status);
    });
  }

  getObs(): Observable<Status> {
    return this.subject.asObservable();
  }

  sendMsg(msg): void {
    this.subject.next(msg);
  }
}

【讨论】:

    【解决方案2】:

    【讨论】:

    • 我们不知道正在使用什么样的主题——它只是被转换为Subject&lt;Status&gt;——这并不意味着它实际上是一个普通的Subject。我们需要有关代码的更多信息。
    • alligator.io/rxjs/subjects 有关主题的详细信息。确定不是行为主体。您可以使用如下行为主题。 ` 私有类别:BehaviorSubject = new BehaviorSubject({});`
    • 我很清楚不同类型的主题。 OP 显然需要ReplaySubject,因为没有初始状态。但我们不知道wsService.connect(url) 返回什么,所以任何答案都只是猜测
    猜你喜欢
    • 1970-01-01
    • 2021-10-07
    • 1970-01-01
    • 2018-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-23
    • 2023-03-07
    相关资源
    最近更新 更多