当React遇到嵌套在另一个中的数组时会发生什么?

neo*_*neo 6 javascript reactjs

当React渲染数组时,应为该数组中的每个项目提供一个键.否则,将发出警告:

Warning: Each child in an array or iterator should have a unique "key" prop
Run Code Online (Sandbox Code Playgroud)

React Doc中有关于如何识别密钥以及我们为什么这样做的详细说明.

但是在这种情况下,我发现当渲染嵌套在另一个数组中的数组时没有给出警告.

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((numbers) =>
  <li>{numbers}</li>
);

// 'listItems' is wrapped in an array
ReactDOM.render(
  <ul>{[listItems]}</ul>,
  document.getElementById('container')
);
Run Code Online (Sandbox Code Playgroud)

在调试之后,在React中,我发现function validateChildKeys,它用于验证子项的键:

/**
 * file path: react/lib/ReactElementValidator.js
 * Ensure that every element either is passed in a static location, in an
 * array with an explicit keys property defined, or in an object literal
 * with valid key property.
 *
 * @internal
 * @param {ReactNode} node Statically passed child of any type.
 * @param {*} parentType node's parent's type.
 */
function validateChildKeys(node, parentType) {
  if (typeof node !== 'object') {
    return;
  }
  if (Array.isArray(node)) {
    for (var i = 0; i < node.length; i++) {
      var child = node[i];
      if (ReactElement.isValidElement(child)) {
        validateExplicitKey(child, parentType);
      }
    }
  } else {
    // do some other validation
    // ..................
  }
}
Run Code Online (Sandbox Code Playgroud)

function ReactElement.isValidElement(child)用于检查是否应检查子节点.

ReactElement.isValidElement = function (object) {
  return typeof object === 'object' && object !== null && object.$$typeof === REACT_ELEMENT_TYPE;
}
Run Code Online (Sandbox Code Playgroud)

当检查嵌套数组时,例如array = [array0,array1,array2],array0,array1,array2是Array没有命名属性的对象,$$typeof因此validateExplicitKey永远不会调用函数,永远不会检查子节点,当然,永远不会抛出警告消息.

我想知道:

  1. React默认这个吗?
  2. 重新渲染时会产生什么影响?
  3. 它对性能有影响吗?如果是的话,当我想渲染这段代码时如何避免这种情况:

    const Page = (tables) => (
       tables.map((table, idx) => (
          [<Title/>,
            ...(table.get('forms').map((form, aidx) => (<Form/>)))
          ]
       ))
    );
    
    Run Code Online (Sandbox Code Playgroud)

小智 0

我认为您提出的案例实际上在上面的评论中进行了描述validateChildKeys

确保每个元素都通过静态位置、定义了显式键属性的数组或具有有效键属性的对象文字传递。

由于您的listItems数组仅声明一次并且不会在渲染时重新计算,因此 React 假设它不需要键来区分后续渲染中的元素。

如果将数组声明移动到渲染函数中,即使数组是嵌套的,您也会再次看到错误:

const numbers = [1, 2, 3, 4, 5];

// 'listItems' is wrapped in an array
ReactDOM.render(
  <ul>
    {[numbers.map((numbers) => <li>{numbers}</li>)]}
  </ul>,
  document.getElementById('container')
);
Run Code Online (Sandbox Code Playgroud)