【发布时间】:2018-02-23 12:22:45
【问题描述】:
有可能吗?
我有一个组件,其中子级由作为props 的任意映射函数呈现。一个简化的例子:
class SomeComponent extends Component {
render() {
const { renderChild, businessObjects } = this.props
return <div>
{businessObjects.map(renderChild)}
</div>
}
}
我显然收到一条警告,说子级渲染时没有 key 属性。
我尝试在渲染 vdom 元素后分配键:
...
{
businessObjects.map(e => {
const vdom = renderChild(e)
vdom.key = e.id
return vdom
})
}
...
但是从 JSX 转换返回的对象被冻结了,所以我不能这样做。也没有 API 可以暂时解冻然后重新冻结 js 中的对象。出于性能原因,克隆是不可能的(成千上万的组件都是这样渲染的)
我能做什么?
同样,出于性能原因,我无法将渲染的子组件包装到另一个组件中,因此这样的解决方案不起作用:
const Child = ({renderChild, bo}) => (<div>{renderChild(bo)}</div>)
// in SomeComponent
...
{
businessObjects.map(e => (<Child
key={e.id}
bo={e}
renderChild={renderChild}
/>)
)
}
...
更新
这种结构的原因是SomeComponent 是一个哑组件,无法访问应用程序状态(redux)。但是渲染的孩子确实需要访问dispatch(我以连接动作创建者的形式这样做)。
所以你可以想象整个事情是这样的:
const createChildRenderer = ({actionFoo, actionBar}) => (obj) => {
switch(obj.type) {
case FOO:
return <div onClick={() => actionFoo()}>{obj.text}</div>
case BAR:
return <div onClick={() => actionBar()}>{obj.text}</div>
default:
return null
}
}
在一个连通分量中
@connect(
({ businessObjects }) => { businessObjects },
{ actionFoo, actionBar}
)
class SmartComponent extends Component {
render() {
const renderChild = createChildRenderer({
actionFoo: this.props.actionFoo, // action creators
actionBar: this.props.actionBar
})
return (<SomeComponent
renderChild={renderChild}
businessObjects={this.props.businessObjects}>
}
}
【问题讨论】:
-
renderChild 函数在哪里?
-
@VamshiGudipati 不相关,这是一个任意的
Object => VDom函数。 -
确实如此。您正在将键分配给 vdom 对象,而不是 HTML 或包装 HTML 的 div
-
@BalázsÉdes,它实际上非常相关。至少让我们看看。这将使这更容易理解。
-
我相信你需要的是
React.createElement()(或者React.cloneElement(),如果你自己创建元素)