首页 文章

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

提问于
浏览
4

很标准的情况 .

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

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

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

The questions are

  • 为什么会发生这种情况并且是预期的行为 .

  • 它如何影响性能

  • 如何避免 - 每个子组件/检测更改只能调用一次 .

Example & plnkr

plnkr (click on item - open console for debug output)

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'
      };
  }
}

2 回答

  • 0
    [ngStyle]="setStyles()"
    

    每次运行更改检测时都会调用 setStyles (这可能经常会影响性能) . 另外因为 setStyles() 每次都返回一个不同的对象实例,所以它应该导致异常 . "Expression changed since it was last checked"或类似的 .

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

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

    [ngStyle]="myStyles"
    
  • 3

    默认情况下( development mode )角运行检测更改机制 twice .
    production mode 中,它减少到 single change .

    如何将Detect Changes机制切换为 生产环境 ?

    main.ts 文件中尝试添加:

    import { enableProdMode } from '@angular/core';
    // ...
    enableProdMode();
    // ...
    platformBrowserDynamic().bootstrapModule(AppModule)
    

    并重新加载应用程序 .

相关问题