中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

html列表中的key屬性有什么用

發布時間:2022-03-03 11:28:39 來源:億速云 閱讀:1665 作者:小新 欄目:web開發

這篇文章給大家分享的是有關html列表中的key屬性有什么用的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

diff 算法的時間復雜度是 O(n), 它的實現是基于以下兩個假設:

兩個 type 不同的元素生成不同的 DOM 樹;

在兩次渲染中,React 能通過 key 屬性判斷哪一個子元素保持不變;

本文內容圍繞「假設 2」展開說明 diff 算法是怎么做到 O(n) 的時間復雜度的。

如果沒有 key 屬性

當遍歷子元素列表的時候,React 會同時遍歷新舊子元素列表,一旦遇到兩個列表有不同的地方,就會生成一個 mutation。

<ul>

  <li>Duke</li>

  <li>Villanova</li>

</ul>

<ul>

  <li>Connecticut</li>

  <li>Duke</li>

  <li>Villanova</li>

</ul>

例如,當在子元素列表之前添加一個元素的時候,如果沒有 key 屬性,React 會同時遍歷新舊子元素數組:

第一個 li 標簽有變化,更新;

第二個 li 標簽有變化,更新;

最后插入第三個 li 標簽;

這個算法的時間復雜度是 O(n),但是會導致很多不必要的 DOM 操作,性能低下。如果通過一種列表對比算法能避免掉不必要的 DOM 操作,就能優化性能。

Levenshtein Distance 算法

為了使用算法優化性能,讓我們對上面的問題做一個抽象,舊的子元素列表:

[1, 2, 3, 4, 5] 

進行了一系列 DOM 節點的刪除、插入、修改的操作之后,得到新的列表:

[6, 3, 1, 2, 5, 4] 

知道了新舊的順序求最小的插入、刪除、修改操作,這是數組的最小編輯距離問題。最常見的是 Levenshtein Distance 算法。

舉一個例子:求 beaut( [公式] ) 和 ebau( [公式] ) 的最小編輯距離,其中 [公式] 是未知字符。動態規劃算法是通過拆分問題,定義問題狀態和狀態之間的關系,使得問題能夠以遞推(或者說分治)的方式去解決。定義長度為「i - 1」的字符串 str1 和長度為「j - 1」的字符串 str2 的最小編輯距離為 [公式] ,那么 beaut( [公式] )和 ebau( [公式] ) 的最小編輯記 [公式] ,[公式] 能且只能基于下面三個狀態:

「狀態 1」 :beaut( [公式] ) 和 ebau 的最小編輯距離已知,記為 [公式] ;

「狀態 2」:beaut 和 ebau( [公式] ) 的最小編輯距離已知,記為 [公式] ;

「狀態 3」:beaut 和 ebau 的最小編輯距離已知,記為 [公式] ;

[公式] 和三個狀態之間的關系分別為下面三個公式:

[公式]

[公式]

[公式]

解釋一下第三個公式,在 [公式] 的情況下, [公式] ;如果 [公式] ,那么 [公式] 。那么上面三個公式值最小的那個就是 [公式] 的解。對照著下圖看,也就是 [公式] 的值可以通過其上方,左邊,左上對角線的值確定,公式如下:

[公式]

[公式]

[公式]

function minDistance(s1, s2) {

    const len1 = s1.length

    const len2 = s2.length

    let matrix = []

    for (let i = 0; i <= len1; i++) {

        // 構造二維數組

        matrix[i] = new Array()

        for (let j = 0; j <= len2; j++) {

            // 初始化

            if (i == 0) {

                matrix[i][j] = j

            } else if (j == 0) {

                matrix[i][j] = i

            } else {

                // 進行最小值分析

                let cost = 0

                if (s1[i - 1] != s2[j - 1]) { // 相同為0,不同置1

                    cost = 1

                }

                const temp = matrix[i - 1][j - 1] + cost

                matrix[i][j] = Math.min(matrix[i - 1][j] + 1, matrix[i][j - 1] + 1, temp)

            }

        }

    }

    return matrix[len1][len2] //返回右下角的值

}

從上面的代碼可以看出,LD 算法有兩個嵌套的 for 循環,所以時間復雜度是 O(n*m),其中 n 為 str1 的長度,m 為 str2 的長度。如果采用 LD 算法,雖然能避免掉不必要的 DOM 操作,但是 diff 算法的時間復雜度就達不到線性了。

key 屬性的引入思路

直接應用 LP 算法不能解決我們的問題。我們并不需要找到真正的最小編輯距離,而是需要找到一種算法,這個算法的時間復雜度必須是 O(n),并且能避免掉大部分的 DOM 操作,而前端的列表大部分的操作是子元素的移動。通過引入 key 屬性唯一標識子元素,我們可以把最小編輯距離轉化成:key 屬性是對這個元素的唯一標識,在這個條件下,求新舊子元素列表的最小插入、刪除、移動操作。這是一種啟發式算法。

舊的子元素列表:

[{ key: 1, val: 1 }, { key: 2, val: 2 }, { key: 3, val: 3 }]

新的子元素列表:

[{ key: 4, val: 4 }, { key: 1, val: 1 }, { key: 3, val: 3 }, { key: 2, val: 2 }]

React 子元素近似最小編輯距離算法

為了尋找上面兩個數組的近似最小編輯距離,React 的做法為,正向遍歷新的子元素,用新的子元素的 key 值去舊的子元素中查找,如果沒找到,就做插入;如果找到了就做移動操作;如果遇到舊的子元素在新的列表中找不到的情況,刪除舊的子元素。算法的時間復雜度是 O(n)。 舉一個例子,如下圖,上一排是舊的子元素列表,下一排是新的子元素列表:

代碼如下,正向遍歷 nextChildren:

「元素 6」: 是新增元素,新增到 index = 0 的位置;

「元素 3」: 不變;

「元素 1」: 元素 1 在原數組中的位置在元素 3 之前,所以需要移動到元素 3 的后面;

「元素 2」: 元素 2 在原數組中的位置也位于 3 之前,移動到元素 1 的后面;

「元素 5」: 不變;

「元素 4」: 移動到 5 后面;

updateChildren() {

  // find removed

  const removedNodes = findRemoved();

  var updates = [];

  var lastIndex = 0;

  var nextIndex = 0;

  var lastPlacedNode = null;

  for (const name in nextChildren) {

    var prevChild = prevChildren && prevChildren[name];

    var nextChild = nextChildren[name];

    if (prevChild === nextChild) {

      // 移動子元素

      if (prevChild._mountIndex < lastIndex) {

        updates.push({

          type: "MOVE_EXISTING",

          fromIndex: prevChild._mountIndex,

          toIndex: nextIndex,

          afterNode: afterNode

        })

      }

      lastIndex = Math.max(prevChild._mountIndex, lastIndex);

      prevChild._mountIndex = nextIndex;

    } else {

      if (prevChild) {

        lastIndex = Math.max(prevChild._mountIndex, lastIndex);

      }

      // 新增子元素

      updates.push({

        type: "INSERT_MARKUP",

        toIndex: nextIndex,

        content: nextChild

      });

    }

    nextIndex++;

    lastPlacedNode = getNativeNode(nextChild); // 獲取 nextChild 對應的 DOM 節點

  }

  // 刪除

  for (const name in removedNodes) {

    updates.push({

      type: "REMOVE_NODE",

      content: null,

      fromIndex: prevChildren[name]._mountIndex,

      fromNode: removedNodes[name]

    })

  }

}

和 Vue 的比較

Vue 對子元素的 diff 的思路和 React 一樣,都引入了「key 是子元素的唯一標識」這一先決條件。在引入這一條件后,比 React 做了更多的優化,Vue 是從新老子元素列表的兩頭向中間遍歷,并多做了一些特殊判斷。就列表更新這一塊,Vue 的性能高于 React。而在 Fiber 架構中,由于沒有反向指針,React 不容易做到通過雙向遍歷優化子元素 diff 算法。

key 屬性最佳實踐

key 屬性幫助 React 識別哪些元素改變了,哪些元素是新增的,哪些被刪除了。元素列表中的元素的 key 值應該是穩定的,能起到唯一標識的作用。下面列舉一些最佳實踐:

1. 使用能在子元素列表之間能唯一標識這個子元素的字符串做為其 key 屬性。用數組的 index 做為 key 值是一種反模式,需要避免。

const todoItems = todos.map((todo) =>

  <li key={todo.id}>

    {todo.text}

  </li>

);

2. key 會傳遞信息給 React ,但不會傳遞給你的組件。如果你的組件中需要使用 key 屬性的值,請用其他屬性名顯式傳遞這個值。

const content = posts.map((post) =>

  <Post

    key={post.id}

    id={post.id}

    title={post.title} />

);

感謝各位的閱讀!關于“html列表中的key屬性有什么用”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

渭源县| 张家口市| 三门县| 东莞市| 台南县| 东乌| 南溪县| 壤塘县| 富平县| 彭阳县| 柳州市| 凌源市| 潜江市| 尚义县| 舞钢市| 左贡县| 湘阴县| 岫岩| 大田县| 桑植县| 沾益县| 博客| 台东县| 包头市| 涞源县| 巴林右旗| 长宁区| 乐安县| 昌邑市| 潼关县| 永昌县| 綦江县| 高阳县| 布拖县| 叙永县| 延津县| 鄄城县| 无为县| 凤城市| 永川市| 云阳县|