2017-03-10 21 views
3

我注意到我可以傳遞給React一組嵌套數組,它會正確渲染項目,但是當我這樣走時,它不會抱怨缺少key s在我的元素上。React中的平面陣列vs嵌套陣列的處理方式不同

const stuff = 'a,b,c'; 

// Nested Array 
// React is fine with it and automatically assigns keys 
// Sample data: [[a, <br />], [b, <br />], [c, <br />]] 
const Foo =() => <div>{stuff.split(',').map(itm => [itm, <br />])}</div>; 

// Flat Array 
// React warns me that I should assign a key to each element in array 
// Sample data: [a, <br />, b, <br />, c, <br />] 
const Bar =() => <div>{stuff.split(',').map(itm => [itm, <br />]).reduce((a, b) => a.concat(b), [])}</div>; 

樣品筆:

https://codepen.io/FezVrasta/pen/NppLPR

它爲什麼會發生?我無法在「自動分配的鍵」上找到對React中「嵌套數組」的任何引用。

+0

對於兒童的數組,請使用[keyed fragments](https://facebook.github.io/react/docs/create-fragment.html)。文檔承認無法將「key」屬性添加到本地陣列並提供「react-addons-create-fragment」包來處理它們。 –

回答

4

您會注意到,即使將警告打印到控制檯,React仍會在您生成的HTML中顯示FooBar。 React使用獨特的密鑰進行對帳,同時嘗試提高渲染性能。您可以在React reconciliation recursing on children頁面閱讀更多關於此的信息。不提供密鑰意味着React不能像它設計的那樣保持高性能。

至於你的問題,爲什麼一個警告是不是輸出到控制檯嵌套的數組,我們要深入到源代碼:

產生警告被稱爲validateExplicitKey,和生活中的作用ReactElementValidator.js模塊。

該功能用於在validateChildKeys在同一模塊中 - 尋找到的源代碼給出了以下,作爲進行反應15.4.2:

function validateChildKeys(node, parentType) { 
    if (typeof node !== 'object') { 
    return; 
    } 
    if (Array.isArray(node)) {      // 1. 
    for (var i = 0; i < node.length; i++) { 
     var child = node[i];      // 2. 
     if (ReactElement.isValidElement(child)) { // 3. 
     validateExplicitKey(child, parentType); 
     } 
    } 
    } else if (ReactElement.isValidElement(node)) { 
    // This element was passed in a valid location. 
    if (node._store) { 
     node._store.validated = true; 
    } 
    } else if (node) { 
    var iteratorFn = getIteratorFn(node); 
    // Entry iterators provide implicit keys. 
    if (iteratorFn) { 
     if (iteratorFn !== node.entries) { 
     var iterator = iteratorFn.call(node); 
     var step; 
     while (!(step = iterator.next()).done) { 
      if (ReactElement.isValidElement(step.value)) { 
      validateExplicitKey(step.value, parentType); 
      } 
     } 
     } 
    } 
    } 
} 
  1. 數組的數組將進入第一代碼方框
  2. child將被設置爲child = ["b", Object]
  3. 的(其中「對象」是反應的虛擬DOM表示爲br節點我們通過JSX創建)

    ReactElement.isValidElement = function (object) { 
        return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE; 
    }; 
    

REACT_ELEMENT_TYPE被設置爲:陣列將通過功能ReactElement.isValidElement運行

var REACT_ELEMENT_TYPE = typeof Symbol === 'function' && Symbol['for'] && Symbol['for']('react.element') || 0xeac7; 

陣列是一個對象,並且不是null,但它是$$typeof屬性還沒有被設置在這裏,所以檢查失敗。

$$typeof尚未設置,因爲React只會將此屬性添加到它創建的元素中,以確定某物是否爲React元素。這包括原生HTML元素,而不是數據類型。

因此,ReactElement.isValidElement檢查失敗,並且從不顯示警告。

+0

謝謝!所以...這是一個錯誤,對吧? –

+0

我在他們的repo上打開了一個問題https://github.com/facebook/react/issues/9174 –

+0

按照我的理解,是的! 'react-dom'中的函數'traverseAllChildrenImpl'知道如何遍歷多維數組中的子類(它遞歸地調用它自己來構建子節點),但'validateExplicitKey'函數不會這樣做 – Anuj

1

我最近一直想知道同樣的事情!

從我在ReactJS的官方文檔已經瞭解有關how the keys work,我希望得到與嵌套陣列數據的同樣的警告,就像一個與陣列的數據,因爲在這兩種沒有設置關鍵屬性的情況。

鍵幫助React識別哪些項目已更改,添加或刪除。鍵應被賦予數組內的元素以給元素一個穩定的標識。

我實際上填補了bug report (issue) in the ReactJS official GitHub repo,描述你所指出同樣的情況,但簡化的(沒有花俏的.map().reduce()一樣的東西)。

它看起來像錯誤給我。 PS:我會在React團隊迴應我時立即更新我的答案。