nz-tab与路由监听引发的死循环

422 阅读1分钟

1. 问题复现

快速在两个tab之间来回点击多次后,造成页面死循环:在这两个tab之间不停来回切换

2. 代码实现

  1. html
<nz-tabset
    (nzSelectChange)="onTabChange($event)"
    [(nzSelectedIndex)]="selectedTabIndex"
  >
  1. ts
  // 切换tab
  public onTabChange(event: NzTabChangeEvent) {
    const {index} = event;
    const type = this.routerLinkList[index];
    this.router.navigate(['.'], {
      queryParams: {type},
      queryParamsHandling: 'merge',
    });
  }
  
  // 监听路由参数变化
  private watchRoute() {
    this.route.queryParams.subscribe((params) => {
        this.selectedTabIndex = this.tabTitleList.findIndex(
          (item) => item.key === type
        );
    });
  }

3. 原因分析

  private watchRoute() {
    this.route.queryParams.subscribe((params) => {
        this.selectedTabIndex = this.tabTitleList.findIndex(
          (item) => item.key === type
        ); // 此方法为异步操作,对selectedTabIndex赋值前后,值可能不一致,触发nzSelectChange事件,造成死循环
    });
  }

问题模型:

  1. onTabChange(A) 触发异步方法watchRoute(B): A=>B
  2. B方法中对selectedTabIndex的赋值又会触发A: B=>A 步骤2是有条件触发:基于angular变更监测,selectedTabIndex赋值前后若值有变则触发onTabChange事件,所以这是一个偶现问题

4. 解决

watchRoute的目的是根据路由参数选中对应的nz-tab,这个只需要在首次加载时有用

  // 监听路由参数变化
  private watchRoute() {
    this.route.queryParams.subscribe((params) => {
        // 首次加载时再选中
        if (isFirstLoad) {
            this.selectedTabIndex = this.tabTitleList.findIndex(
              (item) => item.key === type
            );
            this.isFirstLoad = false;
        }
    });
  }