在react开发中,在某些场景会遇到如下组件嵌套形式的开发,比如说tab组件,下拉框组件等等
<RadioGroup>
<RadioOption label="选项一" value="1" />
<RadioOption label="选项二" value="2" />
</RadioGroup>
如果想把父组件中的属性传给所有的子组件,该怎么做呢?
如果子组件想调用父组件内部的方法,又该怎么做呢?
下面通过一个demo,来回答这俩个问题,不过在此之前需要理解以下一些概念
- this.props.children是React内建的一个属性,用来获取组件的子元素(注意:如果子元素为空,this.props.children为undefined,如果子元素有一个,this.props.children为Object,子元素有多个,this.props.children为Array,没错,就是这么坑,但别急,请看下一条)
- react提供React.Children来处理this.props.children,使用React.Children.map来遍历子节点,不用担心 this.props.children 的数据类型是 undefined 还是 object 还是 Array,方法内部已经做了处理,就是这么酷
- React.cloneElement克隆并返回一个新的 ReactElement (内部子元素也会跟着克隆),新返回的元素会保留有旧元素的 props、ref、key,也会集成新的 props(只要在第二个参数中有定义)。
回到demo,我们写一个radio选择的组件,将radio组合起来,这样就要求radio的name一致,父组件为RadioGroup,name属性在父组件中设置:
class RadioOption extends React.Component{
render() {
return (
<label>
<input type="radio" value={this.props.value} name={this.props.name} onClick={()=>{this.props.showValue(this.props.value)}}/>
{this.props.label}
</label>
);
}
};
class RadioGroup extends React.Component{
//父组件方法
showValue(val){
console.log(val)
}
renderChildren(props) {
//遍历所有子组件
return React.Children.map(this.props.children, child => {
if (child.type === RadioOption)
return React.cloneElement(child, {
//把父组件的props.name赋值给每个子组件(父组件传值给子组件)
name: props.name,
//父组件的方法挂载到props.showValue上,以便子组件内部通过props调用
showValue:this.showValue
})
else
return child
})
}
render() {
return(
<div>
{this.renderChildren(this.props)}
</div>
)
}
};
ReactDOM.render(
<RadioGroup name="option">
<RadioOption label="选项一" value="1" />
<RadioOption label="选项二" value="2" />
</RadioGroup>,
document.getElementById('container')
);
jsfiddle
代码略长,但是仔细看过及阅读注释后,你会对开头提的两个问题豁然开朗。
总结下,其实万变不离其宗,通过React.cloneElement给子元素添加props属性,由于此方法运行在父元素的作用域中,所以可以获取父元素的属性和方法,以此达成通信的目的。