Angular:检查Observable/BehaviorSubject是否有相关变化

Angular: check if Observable / BehaviorSubject has relevant changes

我有一个在会员服务中观察到的用户对象。

我只想在用户对象发生相关变化时更新我的​​服务。

为了了解我的用户对象是否有相关变化,我将我的本地用户对象与观察到的用户对象进行了比较。然后总是分配新对象。

然而,这不起作用。

export class MemberService {
  private subscription?: Subscription;
  user?: User;

  constructor(public auth: AuthService) {
    this.subscription = this.auth.user$.subscribe((user) => {
      const updateServices = this.hasUserRelevantChanges(user)

      // apparently this line always fires before the functioncall above?!
      this.user = user;

      if (updateServices) {
         this.updateMyServices();
      }
    });
  }

  ngOnDestroy() {
    this.subscription?.unsubscribe();
  }

  hasUserRelevantChanges(user: User | undefined): boolean {
      return user?.subscription !== this.user?.subscription ||
          user?.username !== this.user?.username ||
          user?.isBanned !== this.user?.isBanned;
  }

  updateMyServices(): void {
    // Updating my services!!!
  }
}

export class AuthService {
  public readonly user$: Observable<User| undefined> = this.user.asObservable();
  user: BehaviorSubject<User| undefined> = new BehaviorSubject<User| undefined>(undefined);

    constructor(private httpHandler: HttpHandlerService) { ... }

  handleUser(): void {
    this.httpHandler.login().subscribe(
        (user: User) => this.user.next(user));
  }

  updateUserData(newUser: User): void {
    this.user.next(Object.assign(this.user.value, newUser));
  }
}

为什么我的函数 hasUserRelevantChanges() 总是比较相同的新对象?本地 this.user 始终保存此检查中已经存在的新值,即使赋值 this.user = user 之后出现?

那么我如何了解我的新 user 对象与 old/previous 用户对象相比是否更改了相关值?

“为什么我的函数 hasUserRelevantChanges() 总是比较相同的新对象?”

那是因为您总是将新值分配给 this.user 变量。理想情况下,如果不同,您需要使用新的 user 更新它。换句话说,它必须移动到 if 块内。

this.subscription = this.auth.user$.subscribe((user) => {
  const updateServices = this.hasUserRelevantChanges(user)

  if (updateServices) {
    this.user = user;
    this.updateMyServices();
  }
});

更新:pairwise + filter

在您的场景中,您最好使用 RxJS pairwise + filter 运算符来检查条件。

this.subscription = this.auth.user$.pipe(
  pairwise(),
  filter(([user1, user2]) => (
    user1?.subscription !== user2?.subscription ||
    user1?.username !== user2?.username ||
    user1?.isBanned !== user2?.isBanned;
  ))
).subscribe(([user1, user2]) => {    // <-- Update 2: ignore `user1`
  this.updateMyServices(user2);
);

如果您实际上是将对象的所有属性与其之前的值进行比较,则可以将整个 pairwise + filter 替换为 distinctUntilChanged 运算符。

使用 RxJs 操作符。您不需要将用户存储在代码中的某个位置,但您可以使用 pairwisefilter pipe 它。所以它会是这样的:

this.auth.user$.pipe(
           pairwise(), 
           filter(users => userChanged(users[0], users[1]))
           ... // other operators to handle change - tap, map etc
           )

如果将逻辑移至适当的运算符,将会更加清晰。

编辑:Pairwise returns 两个值:以前的和当前的,filter - 正如名称所说过滤事件并仅在传递回调时发出下一个 returns true

Edit2:您应该实施 userChanged 或调整您的 hasUserRelevantChanges,现在您需要传递 2 个参数。

Edit3:为什么您的代码不起作用?因为 Object.assign 不会创建新的对象引用,而是会更改原始对象 - 所以实际上,您每次都在检查同一个对象。

更新:传播运算符:

updateUserData(newUser: User): void {
this.user.next({...this.user.value, ...newUser});

}