Angular2 模板表达式在更改检测时为每个组件调用两次

Ale*_*kov 5 angular2-template angular2-changedetection angular2-components angular

相当标准的情况。

有一个父组件<item-list>。在其模板内*ngFor生成了 20 个子组件<item-block>[ngStyle]使用调用 function 的指令和模板表达式设置子组件样式setStyles()

问题(或可能不是)是,当在一个特定子元素上发出任何事件时,表达式setStyles()会对每个子组件执行两次。

因此,如果我们单击示例中的一个特定项目,并且我们有 20 个<item-block>组件 -setStyles()将执行 20+20 次。

问题是

  1. 为什么会发生这种情况以及这是预期的行为吗?
  2. 它如何影响性能
  3. 如何避免这种情况 - 每个子组件/检测更改仅调用一次。

示例&plnkr

plnkr(单击项目 - 打开控制台以进行调试输出)

import {Component} from '@angular/core'

@Component({
  selector: 'item-list',
  template: `
    <item-block
        [item]="item"
        *ngFor="let item of items"
    ></item-block>
  `,
})
export class ItemListComponent {

  items: any[] = [];

  constructor() {}

  ngOnInit() {
     // generate dummy empty items
    for (let i = 0; i < 20; i++) {
      this.items.push(
        {
          value: 'item #' + i; 
        }
      )
    }
  }
}

import {Component, Input} from '@angular/core'

@Component({
  selector: 'item-block',
  template: `
    <div
      class="item"
      [ngStyle]="setStyles()"
      (click)="testClick($event)"
    >{{item.value}}</div>
  `,
})
export class ItemBlockComponent {

  @Input() item: any;

  constructor() {}

  testClick(): void{
      console.log('item clicked');
  }

  setStyles(){
      console.log('seting styles...');
      return {
          'background': '#ccc'
      };
  }
}
Run Code Online (Sandbox Code Playgroud)

Gün*_*uer 3

[ngStyle]="setStyles()"
Run Code Online (Sandbox Code Playgroud)

导致setStyles每次运行更改检测时都会调用(这可能很频繁并且会损害性能)。另外,由于setStyles()每次返回不同的对象实例,因此应该会导致异常。“自上次检查以来表达式已更改”或类似内容。

不鼓励以这种方式从视图调用方法。

而是将值分配给属性并绑定到该属性:

[ngStyle]="myStyles"
Run Code Online (Sandbox Code Playgroud)