為什麼要在 React 中使用 key
屬性,一切的原因都是 "效能"。
主要的問題是, 每次應用程式渲染 Reacrt 時,都會建立一個新的 react 元素樹,這裡的問題是更新 UI 為了匹配在渲染中建立出來的新 react 元素樹。React 提供了一個聰明的做法讓解決這件事的時間複雜度從 O(n^3) 降低至 O(n),提供了以下二種假設
- 如果一個元素改變它的類型,就會建立一個新的樹
- 如果二個元素在兩顆樹中都有相同的
key
id,則它們是相同的元素,不會從 0 重新渲染
該演算法取決於根元素,有一些不同的做法。如果根元素變更另一種類型(或變更另一個標籤),將會重頭建立新的樹,如下:
<div>
<Counter />
</div>
<span>
<Counter />
</span>
Counter
不會被重新使用,而是會被重新建立掛載
另一個 React 處理很好的情況,是當我們有相同類型的 DOM 元素時,React 只會更新屬性並重用其結構,如下:
<!-- before -->
<img src="images/image.svg" className="something" />
<!-- after -->
<img src="images/image.svg" className="another-something" />
標籤保持不變,React 只會更新 className
屬性
<!-- before -->
<div style={{color: "green", padding: "10px"}}></div>
<!-- after -->
<div style={{color: "orange", padding: "10px"}}></div>
React 只會更新 color
樣式,padding
保持不變
如果節點變更,或不使用節點類型本身,只變更傳遞給它的屬性時,React 都會有所不同。但是有一個問題案例是無法通過查看節點或屬性解決,也就是 Lists
Lists
具有相同的節點類型和屬性,因此它們不會被演算法認可,看下例
<!-- tree1 -->
<ul>
<li>1</li>
<li>2</li>
</ul>
<!-- tree2 -->
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
我們有二個 Lists,React 會匹配前兩二元素(1, 2),並在最後插入一個 (3),但如果我們有一個相似但不同的實作,如下:
<!-- tree1 -->
<ul>
<li>2</li>
<li>3</li>
</ul>
<!-- tree2 -->
<ul>
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
我們在列表的開頭插入了一些新元素。 React 不知道如何處理這個問題,反而會重新建立每個元素,而不是重用在樹之間保變不變的 2 和 3,從而導致效能不佳
這就是 key
很重要的地方。使用 key
,我們可以讓列表每一個項目都有一個唯一的識別代碼(ID), 因此 React 可以輕鬆檢測誰需要變更,或不變更,只重新渲染有變更的那些部分