React.Children.map中的React.cloneElement导致元素键发生更改 [英] React.cloneElement inside React.Children.map is causing element keys to change

查看:188
本文介绍了React.Children.map中的React.cloneElement导致元素键发生更改的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

正如标题所述,在 React.Children.map 中使用 React.cloneElement 导致元素键发生变化。

As the title states, using React.cloneElement inside React.Children.map is causing element keys to change.

这是沙箱,展示了这一点。

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

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

The result of that block of code has elements with .$ added to the front of every key. This is really confusing for two reasons.

1:文档说 cloneElement 将保留密钥和引用。

1: The documentation says that cloneElement will preserve keys and refs.


使用element作为起点克隆并返回一个新的React元素。结果元素将具有原始元素的道具,新道具以浅层方式合并。新的孩子将取代现有的孩子。来自原始元素的key和ref将被保留。

Clone and return a new React element using element as the starting point. The resulting element will have the original element’s props with the new props merged in shallowly. New children will replace existing children. key and ref from the original element will be preserved.

2: console.log <的结果/ code>是一个带有保留键和ref ...的元素。

2: The results of the console.log is an element with preserved keys and ref...

这会让我相信React.Children中的某个地方正在添加。地图代码。

This would lead me to believe that the addition is happening somewhere in the React.Children.map code.

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

UPDATE: After looking at the code for React.Children.map...

I想通过以下功能链添加它:mapChilren - > mapIntoWithKeyPrefixInternal - > traverseAllChildren - > traverseAllChildrenImpl - > mapSingleChildIntoContext。

I figured out it is getting added by the following function chain: mapChilren -> mapIntoWithKeyPrefixInternal -> traverseAllChildren -> traverseAllChildrenImpl -> mapSingleChildIntoContext.

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

mapSingleChildIntoContext's third argument is childKey. It is called with nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar as it's third argument inside traverseAllChildrenImpl.

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

SEPARATOR = "." and getComponentKey returns the key with a $ prefixed to it within the escape function.

更新的问题:

现在我正在寻找解决方法...我不确定如果有一个考虑traverseAllChildrenImpl被一个空字符串调用为traverseAllChildren中的 nameSoFar

Now I'm looking for a way around this... I'm not sure if there is one considering traverseAllChildrenImpl is called with an empty string as the nameSoFar within traverseAllChildren.

我想这可能是用于构建新DOM的 React.Children.map 的预期行为。在尝试更新动态子项上的道具时,这对我来说是个问题。

I think this may be intended the intended behavior of React.Children.map to build new DOM. This is causing a for me when trying to update the props on dynamic children.

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

SOLUTION: Don't use things how they're not intended to be used.

我正在构建一组表单控件,这对开发人员来说非常容易。状态树是通过映射子项和使用来动态构建的。从具有名称的元素描述字符串名称以在顶级组件上创建键和值。

I was building a grouping of form controls that are really easy for the developer. The state tree is dynamically built by mapping the children and using . delineated string names from elements with names to create keys and values on the top level component.

顶级表单组件具有onChange处理程序,用于不同类型的控件并应用它们根据需要添加元素的onChange属性。这个映射是在componentWillMount方法中完成的,也是导致我出现问题的原因。

The top level form component has onChange handlers for different types of controls and they are applied to the onChange properties of elements as needed. This mapping was done in the componentWillMount method and is what was causing me problems.

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

Moving the mapping to the render method allowed me to not have to update the children in the handles. Updating in the handles was causing elements to lose focus. All is good now!

推荐答案

问题不在于 cloneElement 那个改变你的钥匙。如文档中所述,cloneElement保留原始密钥。它的 React.Children.map 为它添加了一个前缀。如果您不想更改密钥,请使用 forEach 而不是 map

The problem is not the cloneElement that changes your keys. As written in the documentation, cloneElement preserves the original keys. Its the React.Children.map that adds a prefix to it. If you don't want the keys to change make use of forEach instead of 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;
}

这篇关于React.Children.map中的React.cloneElement导致元素键发生更改的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆