【问题标题】:BehaviorSubject: why is it working without using nextBehaviorSubject:为什么不使用 next 就可以工作
【发布时间】:2019-11-19 17:39:11
【问题描述】:

我有一个 Angular 应用程序,我为我的联系人列表创建了一个类,其中包括:

export interface Contact {
    id: number;
    name: string;
    address: string;
}

export class ContactList {
    private contactList: Contact[];
    private contactNumber: number;

public getContactList(): Contact[] {
        return this.contactList;
    }

// Methods to add, modify and remove a contact
}

然后我有一个实例化这个类的服务,创建一个 BehaviorSubject 以与其他组件共享它并具有一些公共方法。

export class ContactListService {

  public contactList: ContactList;
  private contactList$: BehaviorSubject<Contact[]>;

  constructor() {
    this.contactList = new ContactList(FAKE_CONTACTS);
    this.contactList$ = new BehaviorSubject<Contact[]>(this.contactList.getContactList());
  }

  public getContactList(): BehaviorSubject<Contact[]> {
    return this.contactList$;
  }

  public deleteContact(contactId: number): void {
    this.contactList.deleteContact(contactId);
  }

  public addContact(newName: string, newAddress: string): void {
    this.contactList.addContact(newName, newAddress);
  }

  public modifyContact(contactId: number, newName?: string, newAddress?: string): void {
    this.contactList.modifyContact(contactId, newName, newAddress);
  }
}

然后,在一个组件中,我订阅了 BehaviorSubject 并将值影响到我的组件的一个属性。

ngOnInit() {
    this.contactListSubscription = this.contactListService.getContactList().subscribe((newContactList) => {
      this.contactList = newContactList;
    });
  }

所以它正在工作(即,当我通过服务执行操作时,所有内容都会随处更新)。但我不明白的是,订阅的内容(即this.contactList = newContactList)只在订阅时执行一次,而不是每次发生动作时执行。即使我通过 contactListService 方法更改内容。即使我取消订阅,比如订阅后 2 秒(例如使用 setTimeout),取消订阅后内容始终是最新的......

起初,我什至不明白为什么它在服务中起作用,而在每次修改对象的操作之后都没有执行contactList$.next(this.contactList.getContactList())

所以看起来我传递了一些引用而不是类的内容?我想我不明白 BehaviorSubject 是如何工作的!

【问题讨论】:

    标签: angular rxjs behaviorsubject


    【解决方案1】:

    JavaScript 总是 传递对对象的引用。

    所以组件中的contactList 数组是对存储在ContactList.contactList 属性中的相同的唯一数组的引用。

    所以,你修改了数组,组件引用了这个修改后的数组,Angular 会检测到数组中的变化,并将这些变化应用到 DOM。

    如果ContactList 中的方法将数组替换为另一个数组(修改后的副本),它将不再起作用,例如

    this.contactList = [this.contactList..., newContact]
    

    在这种情况下,组件将继续引用之前未修改的数组。

    用代码来说明:

    service.contactList = ['John', 'Mary'];
    component.contactList = service.contactList; // the exact, same array
    
    service.contactList.push('Helen'); // add an element to the unique array
    console.log(component.contactList); // logs John, Mary, Helen: it's the same, unique array
    
    service.contactList = ['Jack']; // now the service references a second, different array
    console.log(component.contactList); // Still logs John, Mary, Helen
    

    【讨论】:

    • 所以如果我理解正确的话,这里的 BehaviorSubject 什么都不做!我只是通过它们传递引用。那么我怎样才能实现这样做的正确方法(即传递服务contactList的值,而不是它的引用)?这是一个问题,因为在我的示例中,仅允许服务修改此 contactList 实例的内容吗?
    • 您从 getContactList() 返回数组的副本,以确保内部数组在 ContactList 类之外保持不可修改:return [...this.contactList];。请注意,如果数组中的每个联系人是可变的,这仍然会使它们可以从任何地方修改:数组包含对象的引用
    • 好的!我已经在 J​​ava 项目中遇到过这个问题,我知道这里的行为是一样的。因此,为了改进我的代码,我应该传递(如您所写)数组的副本并在我的服务中的每次修改后在contactList$ 上调用next,以通知每个订阅对象已更新的组件!谢谢
    猜你喜欢
    • 1970-01-01
    • 2020-08-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-22
    • 2021-07-18
    • 2019-11-20
    相关资源
    最近更新 更多