Angular Subject: 仅与一些观察者共享

huangapple go评论66阅读模式
英文:

Angular Subject: share only with some of the observers

问题

以下是您要翻译的内容:

给定一个基本类型

export interface Item {
  id: string;
}

我定义了一个名为BackupClient的类,其中包含一个Subject

export class BackupClient {
  private subject = new Subject<Item>();

  private share(item: Item): void {
    this.subject.next(item);
  }

  public subscribe(observer?: Partial<Observer<Item>>): Subscription {
    return this.subject.subscribe(observer);
  }
}

通过BackupService,组件ItemComponent可以订阅我的BackupClient,并在BackupClient共享新的Item时更新其item

import { BackupClient } from './backup.client';
import { Injectable } from '@angular/core';

@Injectable()
export class BackupService {
  constructor() {}

  public client = new BackupClient();
}
import { BackupService } from '../backup.service';
import { Component, Input } from '@angular/core';
import { Item } from '../item';

@Component({
  selector: 'app-item',
  templateUrl: './item.component.html',
  styleUrls: ['./item.component.css'],
})
export class ItemComponent {
  constructor(private backupService: BackupService) {
    this.backupService.client.subscribe({
      next: (item) => {
        if (this.id === item.id) {
          this.item = item;
        }
      },
    });
  }

  @Input() id?: string | null;

  protected item?: Item | null;
}

在我的应用程序中,现在有许多ItemComponent实例。通过在观察者内部检查id,我可以避免在只有一个item更改时更新所有组件。

我希望通过使用某种类型的Subject或多播设计来改进这一点,仅与具有特定idItemComponent的观察者共享。也就是说,所有组件仍然订阅一个Subject,但共享仅限于具有给定id的那些ItemComponent

StackBlitz

英文:

Given a basic type

export interface Item {
  id: string;
}

I define a class BackupClient with a Subject:

export class BackupClient {
  private subject = new Subject&lt;Item&gt;();

  private share(item: Item): void {
    this.subject.next(item);
  }

  public subscribe(observer?: Partial&lt;Observer&lt;Item&gt;&gt;): Subscription {
    return this.subject.subscribe(observer);
  }
}

Via the BackupService a component ItemComponent may subscribe to my BackupClient and update its item whenever BackupClient shares a new item.

import { BackupClient } from &#39;./backup.client&#39;;
import { Injectable } from &#39;@angular/core&#39;;

@Injectable()
export class BackupService {
  constructor() {}

  public client = new BackupClient();
}
import { BackupService } from &#39;../backup.service&#39;;
import { Component, Input } from &#39;@angular/core&#39;;
import { Item } from &#39;../item&#39;;

@Component({
  selector: &#39;app-item&#39;,
  templateUrl: &#39;./item.component.html&#39;,
  styleUrls: [&#39;./item.component.css&#39;],
})
export class ItemComponent {
  constructor(private backupService: BackupService) {
    this.backupService.client.subscribe({
      next: (item) =&gt; {
        if (this.id === item.id) {
          this.item = item;
        }
      },
    });
  }

  @Input() id?: string | null;

  protected item?: Item | null;
}

In may app I now have many ItemComponent instances. By checking the id inside my observer I avoid an update of all components if only one item changes.

I would like to improve this by using some kind of Subject or multicasting design that only shares with observers of some id. That is, still all components subscribe to one Subject, but sharing is constrained to only those ItemComponents with given id.

StackBlitz

答案1

得分: 1

如果我理解你的意思正确,你希望订阅者只在发出的事件是特定id的项目时才接收这些事件。

在这种情况下,你可以修改你的subscribe()方法,以接受id并过滤掉来自其他项目的事件:

public subscribe(id: string, observer?: Partial<Observer<Item>>): Subscription {
  return this.subject.pipe(
    filter(item => item.id === id)
  ).subscribe(observer);
}
this.backupService.client.subscribe(this.id, ...);

上述代码在构造函数中不起作用,因为@Input() id直到至少ngOnInit()生命周期钩子被调用之前都是未定义的。


你的BackupClient类的subscribe方法可能会引入内存泄漏问题。每当消费者调用.subscribe()时,你都会创建一个订阅,但似乎没有办法取消订阅它们。你可以考虑返回一个Observable,让消费者订阅,然后由消费者负责取消订阅:

public item(id: string) {
  return this.subject.pipe(
    filter(item => item.id === id)
  );
}

然后在你的组件中使用:

this.backupService.client.item(this.id).subscribe(...);
英文:

If I'm understanding you correctly, you want subscribers to only receive emissions if the emission is for an item with a specific id.

In that case, you could modify your subscribe() method to take in the id and filter out emissions from other items:

  public subscribe(id: string, observer?: Partial&lt;Observer&lt;Item&gt;&gt;): Subscription {
    return this.subject.pipe(
        filter(item =&gt; item.id === id)
    ).subscribe(observer);
  }
this.backupService.client.subscribe(this.id, ...);

The above code won't work in the constructor, because the @Input() id will be undefined until at least the ngOnInit() lifecycle hook.


The subscribe method of your BackupClient class is probably introducing memory leaks. Each time a consumer calls .subscribe(), you create a subscription, but it doesn't appear that you have a way to ever unsubscribe from them. You may want to consider returning an Observable that consumers subscribe to, then the consumer can be responsible of unsubscribing:

public item(id: string) {
  return this.subject.pipe(
    filter(item =&gt; item.id === id)
  );
}

Then in your component:

this.backupService.client.item(this.id).subscribe(...);

huangapple
  • 本文由 发表于 2023年2月18日 00:21:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/75486809.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定