倍增订阅

Multiplied subscription

在一个组件中我有两个订阅,一个用于查询参数,一个用于 http GET 请求。 在此页面上,用户还可以选择在不同类型的数据之间切换(只能显示一种类型)。当用户点击一个选项时,查询参数更新,订阅也更新,所以再次调用http GET请求,数据也更新,如下:

constructor(private service: DataService, private route: ActivatedRoute) {}

ngOnInit() {
        this.route.queryParams.subscribe(params => {
            this.dataType = params["dataType"];
                this.service
                    .getData(this.dataType)
                    .subscribe(data => {
                        this.data=data;
                    })
        })
}

在html中:

  [queryParams]="{ dataType: row.dataType}"

问题是,每次用户单击不同类型的数据时,都会从 http GET 请求创建新的订阅,因为一切都发生在同一个组件中。因此,当创建组件时:2 个订阅, 用户点击新数据类型:加载新数据和 3 个订阅,用户点击不同数据类型,加载新数据和 4 个订阅等等。正如您可以想象的那样,点击 4-5 次后页面就会崩溃。

我一直在努力寻找这个问题的解决方案(特别是根据用户的选择在同一组件中加载数据),但我不知道该怎么做。 任何帮助将不胜感激

将您当前的订阅保存在一个变量中,然后在创建新订阅之前将其关闭:

subscription: currSubscribtion;

constructor(private service: DataService, private route: ActivatedRoute) {}

ngOnInit() {
  this.route.queryParams.subscribe(params => {
    if (currSubscribtion) {
      this.currSubscribtion.unsubscribe()
    }
    
    this.dataType = params["dataType"];
    this.currSubscribtion = this.service.getData(this.dataType)
      .subscribe(data => {
          this.data=data;
      })
  })
}

一些 RxJS 管道运算符应该可以解决这个问题:

switchMap - 将取消之前的 http 请求并切换到最新的
使用 takeUntil 方法取消订阅
tap 副作用(在订阅中不这样做有点难看)

ngOnInit() {
  this.route.queryParams.pipe(
    map(params => params["dataType"]),
    tap(dataType => {
      this.dataType = dataType
    }),
    switchMap(dataType => this.service.getData(this.dataType)),
    takeUntil(this.destroyed$)
  ).subscribe(data => {
    this.data = data;
  })
}

编辑 - make takeUntil 最后一个运算符!

此代码无法解决您的问题,但您正在使用两个异步事件中的一个。这不是一个好习惯。

您可以用它来更新您的代码:

this.route.queryParams.pipe(
    switchMap(params => this.service.getData(params["dataType"]))
).subscribe(data => this.data = data);

为了解决您的订阅问题,您是否尝试添加 ngOnDestroy() 功能?

Http 方法是冷可观察对象,因此您无需取消订阅。它将自动取消订阅。

相反,您应该取消订阅 router.queryParams 订阅,这是一个热观察。此订阅已在您的代码中多次创建。

这可以在 ngOnDestroy 生命周期挂钩

中完成
routerSub: Subscription;

constructor(private service: DataService, private route: ActivatedRoute) {}

ngOnInit() {
        this.routerSub = this.route.queryParams.subscribe(params => {
            this.dataType = params["dataType"];
                this.service
                    .getData(this.dataType)
                    .subscribe(data => {
                        this.data=data;
                    })
        })
}

ngOnDestroy() {
    this.routerSub.unsubscribe();
}