在react開發(fā)中,在某些場景會遇到如下組件嵌套形式的開發(fā),比如說tab組件,下拉框組件等等
<RadioGroup>
<RadioOption label="選項一" value="1" />
<RadioOption label="選項二" value="2" />
</RadioGroup>
如果想把父組件中的屬性傳給所有的子組件,該怎么做呢?
如果子組件想調(diào)用父組件內(nèi)部的方法,又該怎么做呢?
下面通過一個demo,來回答這倆個問題,不過在此之前需要理解以下一些概念
- this.props.children是React內(nèi)建的一個屬性,用來獲取組件的子元素(注意:如果子元素為空,this.props.children為undefined,如果子元素有一個,this.props.children為Object,子元素有多個,this.props.children為Array,沒錯,就是這么坑,但別急,請看下一條)
- react提供React.Children來處理this.props.children,使用React.Children.map來遍歷子節(jié)點,不用擔心 this.props.children 的數(shù)據(jù)類型是 undefined 還是 object 還是 Array,方法內(nèi)部已經(jīng)做了處理,就是這么酷
- React.cloneElement克隆并返回一個新的 ReactElement (內(nèi)部子元素也會跟著克?。?,新返回的元素會保留有舊元素的 props、ref、key,也會集成新的 props(只要在第二個參數(shù)中有定義)。
回到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上,以便子組件內(nèi)部通過props調(diào)用
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屬性,由于此方法運行在父元素的作用域中,所以可以獲取父元素的屬性和方法,以此達成通信的目的。