2017-07-25 29 views
2

我正在學習有關角度更改檢測過程並檢查Chrome中的開發工具,我看到了奇怪的行爲。角度更改檢測過程重新繪製dom

我plnkr證明的行爲:http://plnkr.co/edit/cTLF00nQdhVmkHYc8IOu

我的觀點一個簡單的組件:

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

和構造:

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

模擬我添加了一個簡單的要求:

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

如果您注意到,數組list會收到一個等於初始值的列表。讓當角檢查值鑑於變化檢測過程中,我們有這樣的代碼來想象一下:

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

但值相同,爲什麼角重繪每2秒DOM?

但如果我變異的對象,重繪沒有發生

// 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); 

你可以用上面的plnkr鏈接進行測試。

回答

5

這是因爲Angular使用默認trackByFunction作爲DefaultIterableDiffer,它通過身份跟蹤項目。

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

很顯然,當你創建一個新的數組時,它會創建新的對象引用,並且Angular會檢測到變化。即使你沒有改變數組引用,角仍認爲項目改變,因爲對象引用更改:

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

您可以爲您提供定製trackByFunction根據對象名稱來跟蹤:

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

在這樣DOM不會被更新。見this plunker

由於您對ngFor有興趣,您還可以閱讀this answer,我在此解釋ngFor如何工作。

+0

這我不知道,謝謝:) – 0mpurdy

+0

@ 0mpurdy,不客氣,感謝upvote) –

+0

嗨馬克西姆斯,再次感謝你!對於AngularJS開發人員來說'$$ hashKey'是Angular中對象的引用? trackBy for Angular與AngularJS有相同的想法嗎? (相同的概念適用於Angular這篇文章? http://www.codelord.net/2014/04/15/improving-ng-repeat-performance-with-track-by/)? –

1

這是因爲您每次都創建一個新的數組,並且角度正在更新,因爲引用已更改。如果您將其分配到同一個參考每2秒,這將不會是這樣

otherList = [{name: 'Gustavo'}, {name: 'Costa'}]; 

constructor() { 
    this.list = [{name: 'Gustavo'}, {name: 'Costa'}] 
    setInterval(() => { 
    this.list = this.otherList; 
    }, 2000);  
} 

Updated plunker

+0

如果你指定它相同的引用,沒有什麼變化)當然Angular不會更新DOM –

+0

@Maximus我認爲這是他問的是不是?爲什麼如果數組沒有變化,角度仍然會改變檢測 - 答:因爲它是通過引用? – 0mpurdy

+0

不,他問爲什麼udepating數組引用觸發器DOM udpate而突變數組不是 –

1

要添加到@ 0mpurdy,Objects(所以做Arrays)從來都不相等時,即使他們有相同的屬性和值,除非一個是另一個的引用或者它們共享相同的引用。

另一方面,基元可以與其他基元相同,因爲它們是通過值來比較的,而不是通過引用。這就是爲什麼當您爲相同的值手動覆蓋值時沒有觸發更改檢測的原因,但是如果替換整個事件,即使對象明顯相等,也會觸發更改檢測。