代码之家  ›  专栏  ›  技术社区  ›  Robin

使用方法调用而不是ngFor指令的属性时的无限负载

  •  0
  • Robin  · 技术社区  · 6 年前

    在我的模板中,我有以下代码:

    <a *ngFor="let item of navItems"
       [routerLink]="item.link"
       routerLinkActive="active"
       class="navigation-item"
       [ngClass]="{'enabled': item.enabled}"
    >
      <span class="color-{{item.color}}">
        <mat-icon>{{item.icon}}</mat-icon>
      </span>
      <div class="label">{{item.label}}</div>
    </a>
    

    哪里 navItems 是我的组件中的数组:

    navItems: NavItem[] = [
      {
        link: 'link1', label: 'Label 1', icon: 'thumb_up', color: 'green', enabled: true
      },
      {
        link: 'link2', label: 'Label 2', icon: 'thumb_down', color: 'red', enabled: true
      },
      {
        link: 'link3', label: 'Label 3', icon: 'insert_drive_file', color: 'blue', enabled: true
      },
      {
        link: 'link4', label: 'Label 4', icon: 'note_add', color: 'blue', enabled: true
      },
    ];
    

    这很好用。现在,我需要更改此选项,以便navItems可以动态更改。我试着转换 导航项目 属性设置为getter,如下所示:

    get navItems(): NavItem[] {
      return [
        {
          link: 'link1', label: 'Label 1', icon: 'thumb_up', color: 'green', enabled: true
        },
        {
          link: 'link2', label: 'Label 2', icon: 'thumb_down', color: 'red', enabled: true
        },
        {
          link: 'link3', label: 'Label 3', icon: 'insert_drive_file', color: 'blue', enabled: true
        },
        {
          link: 'link4', label: 'Label 4', icon: 'note_add', color: 'blue', enabled: true
        },
      ];
    }
    

    然而,一旦我这样做,浏览器选项卡就会在加载组件时陷入无休止的加载循环,并且必须通过任务管理器终止-我没有控制台输出,什么都没有。

    我还尝试使用普通的方法调用而不是getter来提供数组,结果相同

    我返回的数组仅由具有直接赋值字符串和布尔文字的普通对象组成,因此没有进一步的调用发生,因此不太可能只是我错过了一个递归循环。

    我做错什么了吗?您不能使用方法调用/getter来提供ngFor指令的项吗?

    2 回复  |  直到 6 年前
        1
  •  2
  •   Ampati Hareesh    6 年前

    在这里,当我使用trackBy时,它解决了这个问题

    在html文件中

    <a *ngFor="let item of navItems; trackBy: trackByFn" [routerLink]="item.link" routerLinkActive="active"
    class="navigation-item"
    [ngClass]="{'enabled': item.enabled}"
    >
    <span class="color-{{item.color}}">
     <mat-icon>{{item.icon}}</mat-icon>
    </span>
    <div class="label">{{item.label}}</div>
    </a>
    

    在ts文件中

    export class AppComponent {
       trackByFn(index,item){
         console.log(index,"n:",item);
         return index;
       }
      get navItems(): NavItem[] {
        return [
          {
            link: 'link1', label: 'Label 1', icon: 'thumb_up', color: 'green', enabled: true
          },
          {
            link: 'link2', label: 'Label 2', icon: 'thumb_down', color: 'red', enabled: true
          },
          {
            link: 'link3', label: 'Label 3', icon: 'insert_drive_file', color: 'blue', enabled: true
          },
          {
            link: 'link4', label: 'Label 4', icon: 'note_add', color: 'blue', enabled: true
          },
        ];
      }
    }
    class NavItem {
      link;
       label;
        icon;
         color;
         enabled;
    }
    

    注:

    案例1:没有routerlinkactive[rla]指令,trackBy工作正常

    案例2:rla和trackBy工作正常

    案例3:带rla和无trackBy,-->环

    这里,RouterLinkActive指令实现了[AfterContentInit,and 其他]在此AfterContentInit中有一个方法调用 更新()。。。负责产生这种连续循环。。我 请相信,当该方法返回数组时。。首先是要素 将被创建,然后指令开始对其进行操作。。[供参考: 当update()被注释掉并且没有trackBy时,这也能起作用 很好,因为它不能执行钩子方法。]

    如果观察方法调用navItems,则#个方法调用=#个数组中的项。 每次返回数组时,它都会呈现这些值和指令将作用于现有元素,并且这些指令都有挂钩[AfterContentInit,onDestroy],这些挂钩负责添加元素并销毁类。

    因此,在没有trackBy的情况下,在每个方法返回时,元素将 并且指令将通过将挂钩连接到 在下次方法调用时,它们将被视为新的,并且 指令将执行相同的操作,但会破坏前面的元素。。 这样它就进入了循环。。。

    希望这有帮助!!!

    裁判: https://netbasal.com/angular-2-improve-performance-with-trackby-cc147b5104e5

    Ref:使用源创建CustomRouterLinkActive以进行调试 https://github.com/angular/angular

        2
  •  1
  •   Oscar Paz    6 年前

    我认为这里的问题是,当您在实例变量中使用数组时,数组总是相同的。我的意思是,每次Angular尝试检测更改时,它都检测到数组是相同的,因此它不会执行进一步的操作。

    但是,一旦将实例变量更改为getter,每次调用naviems时都会返回一个新数组。在这种情况下,每次Angular更改检测时,它都会发现一个不同的值。从概念上讲,这些项目是相同的,这并不重要。数组是不同的对象。

    我的意思是,在:

    // if comp is an instance of your component:
    const a = comp.navItems;
    const b = comp.navItems;
    console.log(a === b); // true. a and b are pointers to the same object.
    

    但在你改变之后:

    const a = comp.navItems; // assigning a the return value of a func!
    const b = comp.navItems: // assigninb b the return of a NEW call of a func
    console.log(a === b); // false. Two arrays were created here. Two objects. 
    

    为了避免这个问题,您应该使用trackByFunction,如上所述。这样,只有新的/修改的项目才会再次渲染。您也不应该每次都返回一个新数组,只有在数据确实发生了更改时才返回。如果您仍然希望在getter中以友好的方式构造数组,请考虑使用ChangeDetectionStrategy。ON推入组件,然后使用ChangeDetectorRef。markForCheck()表示组件数据已更改,应在更改检测期间对其进行检查。如果不这样做,Angular将永远不会重新启用组件,除非其任何输入属性发生更改。