BehaviorSubject 值在不需要时返回。有时会重置实际需要的值

BehaviorSubject value is returned when not needed. Sometimes resets the value that is actually needed

我有一个按钮,用于更新组件的参数。当我按下按钮时,这会起作用,它会更新参数。有时,当我刷新页面或从外部页面通过 URL 导航至该页面时,更新逻辑不起作用。

我知道这是因为 behaviorSubject 被硬编码为 (2019,1,1,'Stores'),如下所示。为什么作者把它放在我不确定。我所知道的是刷新时不需要带有 (2019,1,1,'Stores') 的对象。我有一个方法 getSLGCurrentWeek() 也显示在下面,它应该将 (2019,1,1,'Stores') 更新为当前年、季度和周。现在是 2020 年 1,4。

为什么在我尝试重置时显示硬编码值?或者更好的是,什么是从 http 请求 getSLGCurrentWeek() 中获取正确值的最佳方法,以便我可以在 getSLGData(params) 方法中使用这些值?

export class SlgService {

  private slgParamsSource: Subject<SLGReportParams> = new BehaviorSubject<SLGReportParams>(new SLGReportParams(2019, 1, 1, 'Stores'));
  slgParams = this.slgParamsSource.asObservable();

  constructor(private http: HttpClient, @Inject('BASE_URL') private baseUrl: string) { }

  getSLGData(params: SLGReportParams) {
    var slgParams = '?year=' + params.Year + '&quarter=' + params.Quarter + '&week=' + params.Week + '&dept=' + params.Dept;
    return this.http.get(this.baseUrl + 'api/slg/slg' + slgParams);
  }

  getSLGCurrentWeek() {
    return this.http.get(this.baseUrl + 'api/slg/SlgCurrentWeek');
  }

  getSLGWeeks() {
    return this.http.get<any[]>(this.baseUrl + 'api/slg/slgGetAllWeeks');
  }

  updateSLGParams(params: SLGReportParams) {
    this.slgParamsSource.next(params);
  }

}

这是我的 ngOnInit()

  ngOnInit() {

    console.log("here")

    this.slgForm = new FormGroup({
      year: new FormControl(),
      quarter: new FormControl(),
      week: new FormControl(),
      dept: new FormControl()
    })

    console.log(this.slgForm)


    //subscribe to slg Service params observable
    this.slgService.slgParams.subscribe(data => {

      this.slgParams = data;
      this.getData(this.slgParams);
    })


    this.slgService.getSLGCurrentWeek().subscribe((data: any) => {
      //set SlgForm with current week values.
      this.slgForm.patchValue({
        year: data.year,
        week: data.week,
        quarter: data.quarter
      })

      this.slgParams = new SLGReportParams(this.slgForm.value.year, this.slgForm.value.quarter, this.slgForm.value.week, this.slgForm.value.dept);
      this.slgService.updateSLGParams(this.slgParams);

      //this.populateSLGTotals();
      //this.operations(data);
      this.getData(this.slgParams)
      //update service with params // Submit has been taken out here
    },
      error => console.log(error),
    )

  }

更新按钮

  submit() {
    this.slgParams = new SLGReportParams(this.slgForm.value.year, this.slgForm.value.quarter, this.slgForm.value.week, this.slgForm.value.dept);
    this.slgService.updateSLGParams(this.slgParams);
    console.log("I have submitted")
  }

总之。我如何 运行 this.slgService.getSLGCurrentWeek() 在不受 BehaviorSubject (2019,1,1,'Stores') 影响的情况下将参数放入 this.slgService.getSLGData(params)

感谢您的帮助。

Why is that hard coded value showing up when I am trying to reset it?

发生这种情况是因为您正在使用 BehaviorSubject。您提供给 构造函数 的初始值就是您在执行

时最初获得的值
this.slgService.slgParams.subscribe(data => {
 this.slgParams = data;
 this.getData(this.slgParams);
})

这种主题的有趣之处在于它将缓存 最后发出的值。因此,新订阅者将收到该值。

这是我认为您可以使用 skip operator.

跳过第一个发出的值的方法
this.slgService.slgParams
 .pipe(skip(1))
 .subscribe(data => {
   this.slgParams = data;
   this.getData(this.slgParams);
})

这些是非常有趣的代码片段。如果我处在你的位置,我会尝试做类似以下片段的事情。如果您可以在 stackblitz or enter link description here 中重现该问题,我可以为您提供完整的示例。

ngOnInit() {
  this.slgForm = new FormGroup({
    year: new FormControl(),
    quarter: new FormControl(),
    week: new FormControl(),
    dept: new FormControl()
  })

  this.slgService.getSLGCurrentWeek().pipe(
    map(data => {
      this.slgForm.patchValue({
        year: data.year,
        week: data.week,
        quarter: data.quarter
      })
      // Those are your slg params, that you will get as value from the stream
      return new SLGReportParams(data.year, data.quarter, data.week, this.slgForm.value.dept)
    }),
    switchMap(slgParams => {
      // This will return new stream, with the response of the get data http request
      return this.slgService.getSLGData(slgParams);
    })
  ).subscribe(resp => {
    // Here you will have access to the data recieved from the getData function
    console.log(resp)
  })
}

所以我做了不同的事情,而不是依赖于服务内部的 BehaviorSubject,我使用了更 functional/reactive 的方法,我在一个订阅,尝试删除对请求流外部数据的所有依赖。

你可以明白我的意思,通过查看我收集 slgParams 数据的方式,而不是依赖于具有修补值的表单,我直接从"source"(流中接收到的 data 对象)。

一条友好的建议,如果你打算在这个项目上工作更长的时间,我强烈建议你花一些时间学习反应式编程的原则,Angular,rxjs, ngrx.

如果我可以在这里为您的问题提出一些建议 => 您应该非常小心您的订阅:不要忘记 "unsubscribe" 通过实施 ngDestroy 来实现所有订阅。每次您加载组件时,它都会一次又一次地订阅。

如果你想有个主意:转到你的控制台,检查使用的内存,或者至少检查日志,你应该会在一段时间后看到它在屋顶上。

希望对您有所帮助。