我试图找到正确的方法来定义一些组件,这些组件可以以通用的方式使用:
<Parent>
<Child value="1">
<Child value="2">
</Parent>
当然,在父组件和子组件之间呈现有一个逻辑,您可以想象<select>和<option>是这个逻辑的一个例子。
这是为了解决这个问题的一个虚拟实现:
var Parent = React.createClass({
doSomething: function(value) {
},
render: function() {
return (<div>{this.props.children}</div>);
}
});
var Child = React.createClass({
onClick: function() {
this.props.doSomething(this.props.value); // doSomething is undefined
},
render: function() {
return (<div onClick={this.onClick}></div>);
}
});
问题是无论何时使用{this.props。Children}定义一个包装器组件,如何将某些属性传递给它的所有子组件?
我认为渲染道具是处理这种情况的合适方法
你可以让父组件提供子组件中使用的必要的道具,通过重构父组件代码使其看起来像这样:
const Parent = ({children}) => {
const doSomething(value) => {}
return children({ doSomething })
}
然后在子组件中,你可以这样访问父组件提供的函数:
class Child extends React {
onClick() => { this.props.doSomething }
render() {
return (<div onClick={this.onClick}></div>);
}
}
现在最终的结构是这样的:
<Parent>
{(doSomething) =>
(<Fragment>
<Child value="1" doSomething={doSomething}>
<Child value="2" doSomething={doSomething}>
<Fragment />
)}
</Parent>
根据cloneElement()的文档
React.cloneElement(
element,
[props],
[...children]
)
克隆并返回一个新的React元素,使用element作为起始元素
点。生成的元素将具有原始元素的道具
新道具浅浅地融合在一起。新的孩子将取代
现有的儿童。原元素的Key和ref将为
保存了下来。
React.cloneElement()几乎等同于:
<元素。{…元素类型。道具道具}{…}>{孩子}< / element.type >
然而,它也保留了裁判。这意味着如果你有了孩子
有裁判在上面,你就不会不小心从你的祖先那里偷了它。
你会得到相同的引用附加到你的新元素。
因此,您将使用cloneElement为儿童提供自定义道具。然而,组件中可能有多个子组件,您需要循环遍历它。其他答案建议你使用react。children。map来映射它们。然而React. children .map不同于React。cloneElement更改Element附加项和额外的。$作为前缀的键值。查看这个问题了解更多细节:React。React.Children.map中的cloneElement会导致元素键的改变
如果您希望避免它,您应该改用forEach函数,如
render() {
const newElements = [];
React.Children.forEach(this.props.children,
child => newElements.push(
React.cloneElement(
child,
{...this.props, ...customProps}
)
)
)
return (
<div>{newElements}</div>
)
}
Parent.jsx:
import React from 'react';
const doSomething = value => {};
const Parent = props => (
<div>
{
!props || !props.children
? <div>Loading... (required at least one child)</div>
: !props.children.length
? <props.children.type {...props.children.props} doSomething={doSomething} {...props}>{props.children}</props.children.type>
: props.children.map((child, key) =>
React.cloneElement(child, {...props, key, doSomething}))
}
</div>
);
Child.jsx:
import React from 'react';
/* but better import doSomething right here,
or use some flux store (for example redux library) */
export default ({ doSomething, value }) => (
<div onClick={() => doSomething(value)}/>
);
和main.jsx:
import React from 'react';
import { render } from 'react-dom';
import Parent from './Parent';
import Child from './Child';
render(
<Parent>
<Child/>
<Child value='1'/>
<Child value='2'/>
</Parent>,
document.getElementById('...')
);
参见示例:https://plnkr.co/edit/jJHQECrKRrtKlKYRpIWl?p=preview