您是否要请求功能或报告错误?
这是一个错误,或者至少是要求更精确的警告和错误消息的请求。
目前的行为是什么?
我正在克隆子项以添加一些属性,但我忽略了不应复制上下文Consumer子树...
import React from 'react';
import {render} from 'react-dom';
const { Provider, Consumer} = React.createContext();
const Comp = ({children})=> <Provider>{cloneKids(children)}</Provider>;
const cloneKids=(children)=>React.Children.map(children, child =>
React.cloneElement(child, child.props,
child.props.children&&
cloneKids(child.props.children)));
render(
<Comp><Consumer>{console.log}</Consumer></Comp>,
document.getElementById('root')
);
该代码产生#12241引入的警告和错误。
警告:上下文使用者使用多个子项或不是功能的子项进行渲染。 上下文使用者期望一个子元素是一个函数。 如果确实传递了一个函数,请确保该函数周围没有尾随或前导空格。
和(甚至更令人困惑)
TypeError:render不是函数
预期的行为是什么?
也许React.cloneElement不应该尝试克隆函数? 无论做什么,结果都不是函数。
警告部分“不是功能的孩子”应与其他警告分开。 不能有多个孩子和一个孩子不能同时使用,因此可以发出更精确的警告。
哪个版本的React,以及哪个浏览器/操作系统受此问题影响?
已在Stackblitz / Chrome 65中使用React 16.3.0进行测试,并在Chrome 65和Firefox 59中使用React 16.3.2进行了测试
问题不在于cloneElement
(它没有上下文的特殊逻辑),而是您将props.children
(在这种情况下是函数)传递给Children.map()
(不要求功能)。 Children.map
仅适用于常规React节点。
当Children.map
遇到非React节点的内容时,可能会显示警告。
在任何一种情况下,像这样深度克隆React树听起来都像您在尝试做React并非为之设计的事情。 你为什么需要这个?
谢谢!
我推迟了对一些子级属性的评估,直到父级准备好为其评估提供背景为止。 例如:
<Parent ><Child prefix-prop="string expression"></Parent>
(表达式语言不是javascript,并且会进行远程评估。我不控制Child,并且可以有任意数量的child)。
这个孩子在内部变得像:
<Child prop={evaluate("string expression")} />
为此,父级访问子级并将包含表达式的“ prefix-prop”属性转换为包含表达式值的“ prop”属性。 克隆是我发现改变组件属性的唯一方法。 当然,上下文不应该克隆使用者,那里没有可以更改的属性。
我知道我应该使用子函数或渲染函数或类似函数(以延迟评估),但是我正在设计原型库和用户(他们来自HTML和JSP,并且经常是HTML和表达语言以外的新手)将很可能不喜欢这种表示法:
<Parent>{ context=> <Child prop={context.evaluate(x)} />}</Parent>
(此外,如果他们忘记了函数前的空格,则会被#12689所迷惑)
并且他们也不会迅速理解此表格:
<Parent display={ context=> <Child prop={context.evaluate(x)} />} />
上下文使用者也使用子功能,因此他们有相同的问题。
这是非常早期的工作,因此我仍在考虑选择方案,但是我不知何故想要像第一个引号中那样得出一个清晰的父子符号。 可能我应该编写一个babel插件,将“干净”表示法转换为实用的表示法。
但是也许我想念一些东西,所以我将不胜感激。 我真的希望我的用户离开JSP并采用React,但是如果表示法过于含糊,那就不会发生...
我正在考虑的另一个想法是功能父母,可能会返回Component(某种HOC)
({context})=>
context.parent("context expression",
context2=><Child prop={context2.evaluate("sub-expression")} context={context2} />)
Child可以再次包含context.parent()调用,依此类推。
当然parent()可以在返回的组件的render()中使用上下文使用者,因此可以删除上下文属性:
()=>
parent("context expression",
context2=><Child prop={context2.evaluate("sub-expression")} />)
_这里的问题是,作为组件的parent()可以访问React上下文,但是就我所知,评价()无法访问React上下文,除非它返回了一个Component_
实际上尝试设置属性时,这是不可能的。
因此,我认为从外部组件访问React上下文将是理想的。 就像是
React.getContext(Consumer, data=> ...)
如果我没记错的话,在为此苦苦挣扎时,我尝试使用测试框架手动调用Consumer.render(),但没有任何意义。
PS:上面的第一个符号看起来似乎很神秘,但是实际上它对当前的JSP表单非常熟悉,因此我认为我可以将其出售给用户:)
<context:parent ctx="context-expression">
HTML...<context:evaluate expr="sub-expression" />...HTML
</context:parent>
要关闭,因为这似乎并不经常发生。
最有用的评论
问题不在于
cloneElement
(它没有上下文的特殊逻辑),而是您将props.children
(在这种情况下是函数)传递给Children.map()
(不要求功能)。Children.map
仅适用于常规React节点。当
Children.map
遇到非React节点的内容时,可能会显示警告。在任何一种情况下,像这样深度克隆React树听起来都像您在尝试做React并非为之设计的事情。 你为什么需要这个?