React: 克隆上下文使用者的子级会产生令人困惑的警告和错误

创建于 2018-04-25  ·  4评论  ·  资料来源: facebook/react

您是否要请求功能或报告错误
这是一个错误,或者至少是要求更精确的警告和错误消息的请求。

目前的行为是什么?

我正在克隆子项以添加一些属性,但我忽略了不应复制上下文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进行了测试

Question

最有用的评论

问题不在于cloneElement (它没有上下文的特殊逻辑),而是您将props.children (在这种情况下是函数)传递给Children.map() (不要求功能)。 Children.map仅适用于常规React节点。

Children.map遇到非React节点的内容时,可能会显示警告。

在任何一种情况下,像这样深度克隆React树听起来都像您在尝试做React并非为之设计的事情。 你为什么需要这个?

所有4条评论

问题不在于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>

要关闭,因为这似乎并不经常发生。

此页面是否有帮助?
0 / 5 - 0 等级