Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
589 views
in Technique[技术] by (71.8m points)

angular2 changedetection - Angular change detection process repainting the dom

I'm learning about Angular change detection process and I'm checking the Chrome dev tools, I see strange behavior.

My plnkr to demonstrate the behavior: http://plnkr.co/edit/cTLF00nQdhVmkHYc8IOu

I have a simple component view:

<li *ngFor="let item of list">{{item.name}}</li>

and the its constructor:

constructor() {
    this.list = [{name: 'Gustavo'}, {name: 'Costa'}]

to simulate a simple request I've added:

// simulating request repaint the DOM
setInterval( () => {
  this.list = [{name: 'Gustavo'}, {name: 'Costa'}];
}, 2000);

If you noticed, the array list receives a list equal to the initial value. Let's imagine when Angular checks the values in view in change detection process we have a code like this:

if( oldName !== name )  { // ( 'Gustavo' !== 'Gustavo')
 // update the view
}

But the values are the same, why angular REPAINT THE DOM every 2 seconds.?

But if I mutate the object, the REPAINT does not occur

// simulating request there is not repaint
setInterval( () => {
  this.list[0].name = "Gustavo"; // no repaint because it's the same value
  this.list[1].name = "Costa 2"; // repaint
}, 2000);

You can test this with the plnkr link above.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

This is because Angular uses default trackByFunction for the DefaultIterableDiffer that tracks items by identity.

const trackByIdentity = (index: number, item: any) => item;

So obviously when you create a new array it creates new object references and Angular detects changes. Even if you didn't change array reference, Angular will still think that items are changed because object references change:

setInterval( () => {
  this.list.length = 0;
  this.list.push({name: 'Gustavo'});
  this.list.push({name: 'Costa'});
}, 2000);

You can provide you custom trackByFunction to track by object name:

@Component({
  selector: 'my-app',
  template: `
   <li *ngFor="let item of list; trackBy:identify">{{item.name}}</li>
  `
})
export class App {
  list:[];

  identify(index, item){
     return item.name; 
  }

In this way the DOM will not be updated. See this plunker.

Since you are curios about ngFor you can also read this answer where I explain how ngFor works under the hood.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...