【问题标题】:Angular 12, rxjs: unsubscribe to nested subscriptionAngular 12,rxjs:取消订阅嵌套订阅
【发布时间】:2021-11-18 20:37:49
【问题描述】:

我有一个简单的身份验证服务和另一个组件 Foo,它执行以下操作:

  • 获取一些数据(两个列表)
  • 使用这些列表,订阅 auth login observable 以获取更多数据
export class AuthService implements OnInit {
  login: BehaviorSubject<Login | undefined> = new BehaviorSubject<Login | undefined>(undefined);
  public readonly login$: Observable<Login | undefined> = this.login.asObservable();

    constructor(private httpService: HttpHandlerService) { }

    ngOnInit(): void {
        this.httpService.login().subscribe(
            (login: Login) => {
                this.login.next(login);
            });
    }
}

export class Foo implements OnInit {
  subscription?: Subscription;
  listA?: KeyValuePair[];
  listB?: KeyValuePair[];

  constructor(private httpHandlerCached: HttpHandlerCachedService, private auth: AuthService) {
  }

  ngOnInit(): void {
    this.initLists().subscribe(([listA, listB]) => {
      this.listA = listA;
      this.listB = listB;

      this.initModule();
    });
  }

  initLists(): Observable<[KeyValuePair[], KeyValuePair[]]> {
    return forkJoin([
      this.httpHandlerCached.getAllListA(),
      this.httpHandlerCached.getAllListB()
    ]);
  }

  initModule(): void {
    this.auth.login$.subscribe((login) => {
      if (login) {
        this.httpHandler.getSomeData(login.id)
          .subscribe(someData => doSomeStuff(someData, listA, listB));
      }
    })
  }
}

我的尝试:

export class Foo implements OnInit, OnDestroy {
  listA?: KeyValuePair[];
  listB?: KeyValuePair[];
  subscription?: Subscription;

  constructor(private httpHandlerCached: HttpHandlerCachedService, private auth: AuthService) { }

  ngOnInit(): void {
    this.subscription = this.initLists().subscribe(([listA, listB]) => {
      this.listA = listA;
      this.listB = listB;

      this.initModule();
    });
  }

  initLists(): Observable<[KeyValuePair[], KeyValuePair[]]> {
    return forkJoin([
      this.httpHandlerCached.getAllListA(),
      this.httpHandlerCached.getAllListB()
    ]);
  }

  initModule(): void {
    this.subscription = this.auth.login$.subscribe((login) => {
      if (login) {
        this.httpHandler.getSomeData(login.id)
          .subscribe(someData => doSomeStuff(someData, listA, listB));
      }
    })
  }

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

我的问题:

  • 这是分配两个订阅的正确方法吗?
  • 在这两种情况下我都需要退订吗?

谢谢!

【问题讨论】:

  • 您将在第二次调用中覆盖 this.subscription ,因此无论如何这都行不通。但是,整个方法并不真正正确。你真的不应该嵌套订阅。阅读 switchMap 和其他 rxjs 操作符。这种情况下的 switchMap 可以防止嵌套订阅。

标签: angular typescript rxjs


【解决方案1】:

这就是我们避免嵌套订阅的原因之一 - 它使清理变得混乱。而是在管道内使用一些运算符,例如

this.auth.login$.pipe(
    filter(Boolean),
    switchMap(({ id }) => this.httpHandler.getSomeData(id)),
).subscribe(someData => doSomeStuff(someData, listA, listB));

现在只有一个订阅。您可以在销毁时取消订阅,可以使用 takeUntil 模式 (Angular RxJS Observable: takeUntil vs. unsubscribe with a Subscription),甚至可以通过在模板中使用 async 管道来避免显式订阅,具体取决于 doSomeStuff 的实际作用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-10
    • 1970-01-01
    • 2020-02-14
    • 1970-01-01
    • 2021-03-03
    • 1970-01-01
    相关资源
    最近更新 更多