【发布时间】:2018-04-12 05:14:14
【问题描述】:
正如标题所述,在 React.Children.map 内使用 React.cloneElement 会导致元素键发生变化。
这里有一个sandbox 演示了这一点。
React.Children.map(children, (child) => {
let clonedEl = React.cloneElement( child );
console.log(clonedEl);
return clonedEl;
});
该代码块的结果包含带有.$ 的元素添加到每个键的前面。这确实令人困惑,原因有两个。
1:文档说cloneElement 将保留键和引用。
使用 element 作为起点克隆并返回一个新的 React 元素。结果元素将具有原始元素的道具和新道具的浅层合并。新的孩子将取代现有的孩子。原始元素的 key 和 ref 将被保留。
2:console.log 的结果是一个带有保留键和引用的元素...
这会让我相信添加发生在 React.Children.map 代码的某个地方。
更新:查看 React.Children.map 的代码后...
我发现它是由以下函数链添加的:mapChilren -> mapIntoWithKeyPrefixInternal -> traverseAllChildren -> traverseAllChildrenImpl -> mapSingleChildIntoContext。
mapSingleChildIntoContext 的第三个参数是 childKey。它是用nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar 调用的,因为它是traverseAllChildrenImpl 中的第三个参数。
SEPARATOR = "." 和 getComponentKey 在转义函数中返回带有 $ 前缀的键。
更新问题:
现在我正在寻找解决此问题的方法...我不确定是否有人考虑使用空字符串调用 traverseAllChildrenImpl 作为 traverseAllChildren 中的 nameSoFar。
我认为这可能是 React.Children.map 构建新 DOM 的预期行为。当我尝试更新动态孩子的道具时,这对我造成了影响。
解决方案:不要使用不打算使用的东西。
我正在构建一组对开发人员来说非常容易的表单控件。状态树是通过映射子节点并使用 .从具有名称的元素中划定字符串名称,以在顶级组件上创建键和值。
顶级表单组件具有用于不同类型控件的 onChange 处理程序,它们根据需要应用于元素的 onChange 属性。此映射是在 componentWillMount 方法中完成的,这就是导致我出现问题的原因。
将映射移动到渲染方法使我不必更新句柄中的子级。句柄中的更新导致元素失去焦点。现在一切都很好!
【问题讨论】:
-
不完全是您问题的答案,但您可以使用
React.Children.forEach作为替代方案。 -
好点,我可以用forEach“手动”重建孩子。我认为这可能必须解决。我认为这可能是地图的预期行为。
标签: javascript reactjs