Angular2 template expression called twice for each component on change-detection

落花浮王杯 提交于 2019-12-10 17:20:26

问题


Pretty standard situation.

There is one parent component <item-list>. Inside its template with *ngFor generated 20 child components <item-block>. Child component styles set with [ngStyle] directive and template expression that calls function setStyles().

The problem (or maybe not) is that when any event emitted on one specific child element, expression setStyles() executed twice for each of child components.

So if we click on one specific item in our example, and we have 20 <item-block> components - setStyles() will be executed 20+20 times.

The questions are:

  1. Why its happening and is it expected behavior.
  2. How it affect performance
  3. How it could be avoided - only one call per child component/detection change.

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

回答1:


[ngStyle]="setStyles()"

causes setStyles to be called every time change detection is run (which can be quite often and will hurt performance). Also because setStyles() returns a different object instance every time, it should cause an exception. "Expression changed since it was last checked" or similar.

Calling methods from the view this way is discouraged.

Instead assign the value to a property and bind to that property:

[ngStyle]="myStyles"



回答2:


In default (development mode) Angular run Detect Changes mechanism twice.
In production mode it is reduce to single change.

How to switch Detect Changes mechanism to production?

In main.ts file try to add:

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

and reload application.



来源:https://stackoverflow.com/questions/41471232/angular2-template-expression-called-twice-for-each-component-on-change-detection

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!