有可能吗?
我有一个组件,其中子项由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}>
}
}
答案 0 :(得分:0)
您可以对从renderChild
收到的孩子使用cloneElement:
React.cloneElement(
child,
{...child.props, key: yourKeyValue}
)
答案 1 :(得分:0)
我通过将实际的反应组件作为参数来解决这个问题的方式:
因此,在之前采用渲染器功能的哑组件中,现在我采用了一个组件:
class SomeComponent extends Component {
render() {
const { ChildComponent, businessObjects } = this.props
return <div>
{businessObjects.map((o) => (<ChildComponent
businessObject={o}
key={o.id}
/>)}
</div>
}
}
我之前创建了渲染器函数,现在我创建了组件:
const createChildComponent = ({actionFoo, actionBar}) =>
({ businessObject: obj }) => { // this is now a component created dynamically
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 ChildComponent = createChildComponent({
actionFoo: this.props.actionFoo, // action creators
actionBar: this.props.actionBar
})
return (<SomeComponent
ChildComponent={ChildComponent}
businessObjects={this.props.businessObjects}>
}
}