React.Children.map中的React.cloneElement正在导致元素键发生更改

正如标题状态,使用React.cloneElementReact.Children.map导致元素键来改变。

这是一个演示这个的沙箱。

React.Children.map(children, (child) => {
    let clonedEl = React.cloneElement( child );
    console.log(clonedEl);
    return clonedEl;
});

该代码块的结果具有添加到每个键前面的.$元素。 这真是令人困惑,有两个原因。

1:文档说cloneElement将保留键和参考。

使用元素克隆并返回一个新的React元素作为起点。 由此产生的元素将具有原始元素的道具,新道具融合得很浅。 新的孩子将取代现有的孩子。 键和来自原始元素的参考将被保留。

2: console.log的结果是一个保存有键和ref的元素。

这会让我相信这个添加发生在React.Children.map代码的某处。

更新:在查看React.Children.map的代码后...

我想通过下面的函数链添加它:mapChilren - > mapIntoWithKeyPrefixInternal - > traverseAllChildren - > traverseAllChildrenImpl - > mapSingleChildIntoContext。

mapSingleChildIntoContext的第三个参数是childKey。 它被称为nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar因为它是traverseAllChildrenImpl的第三个参数。

SEPARATOR = "." 并且getComponentKey在转义函数中返回带有$前缀的键。

更新的问题:

现在我正在寻找解决此问题的方法...我不确定是否有人考虑traverseAllChildrenImpl在traverseAllChildren中使用空字符串作为nameSoFar

我认为这可能意味着React.Children.map构建新的DOM的预期行为。 当试图更新动态儿童道具时,这对我造成了一定的影响。

解决方案:不要使用他们不打算使用的东西。

我正在构建一组对开发人员非常简单的表单控件。 状态树是通过映射孩子并使用动态构建的。 从具有名称的元素中划定字符串名称以在顶层组件上创建键和值。

顶层表单组件具有onChange处理程序,用于处理不同类型的控件,并根据需要应用于元素的onChange属性。 这个映射是在componentWillMount方法中完成的,是什么导致了我的问题。

将映射移动到渲染方法允许我不必更新句柄中的子项。 手柄更新导致元素失去焦点。 现在一切都很好!


问题不在于更改密钥的cloneElement 。 正如文档中所写,cloneElement保留原始密钥。 它的React.Children.map它添加一个前缀。 如果您不希望密钥更改,请使用forEach而不是map

这是来自React Code的摘录:

function escape(key) {
  var escapeRegex = /[=:]/g;
  var escaperLookup = {
    '=': '=0',
    ':': '=2',
  };
  var escapedString = ('' + key).replace(escapeRegex, function(match) {
    return escaperLookup[match];
  });

  return '$' + escapedString;
}

function getComponentKey(component, index) {
  // Do some typechecking here since we call this blindly. We want to ensure
  // that we don't block potential future ES APIs.
  if (
    typeof component === 'object' &&
    component !== null &&
    component.key != null
  ) {
    // Explicit key
    return escape(component.key);
  }
  // Implicit key determined by the index in the set
  return index.toString(36);
}

function mapSingleChildIntoContext(bookKeeping, child, childKey) {
  var {result, keyPrefix, func, context} = bookKeeping;

  var mappedChild = func.call(context, child, bookKeeping.count++);
  if (Array.isArray(mappedChild)) {
    mapIntoWithKeyPrefixInternal(
      mappedChild,
      result,
      childKey,
      emptyFunction.thatReturnsArgument,
    );
  } else if (mappedChild != null) {
    if (ReactElement.isValidElement(mappedChild)) {
      mappedChild = ReactElement.cloneAndReplaceKey(
        mappedChild,
        // Keep both the (mapped) and old keys if they differ, just as
        // traverseAllChildren used to do for objects as children
        keyPrefix +
          (mappedChild.key && (!child || child.key !== mappedChild.key)
            ? escapeUserProvidedKey(mappedChild.key) + '/'
            : '') +
          childKey,
      );
    }
    result.push(mappedChild);
  }
}

function mapChildren(children, func, context) {
  if (children == null) {
    return children;
  }
  var result = [];
  mapIntoWithKeyPrefixInternal(children, result, null, func, context);
  return result;
}
链接地址: http://www.djcxy.com/p/27565.html

上一篇: React.cloneElement inside React.Children.map is causing element keys to change

下一篇: Using jQuery .attr or .prop to set attribute value not working