好久沒更博了啊,0.0,最近手頭的一個前端控制檯項目,我是用阿里開源的ant框架搭建的,用着還是蠻順手了,在使用過程中,碰到一些數據通信的問題,有些和vue相同,有些不一樣的地方還是踩了些坑的,特地整理了下。
1.子組件調用父級的數據和方法
父級組件代碼如下,把數據和方法通過props向下傳遞,在子組件中調用this.props.text即可獲得父級數據,調用this.props.checkboxCallback()即可調用父級方法
render() {
const text = this.state.text;
const checked = this.state.checked;
return (
<Row>
<Col span={24}>
<ChildComponent
ref="child1"
text={text}
checked={checked}
inputCallback={this.inputCallback}
checkboxCallback={this.checkboxCallback}
>
</ChildComponent>
<button onClick={() => this.log('lemon')}>console</button>
<button onClick={() => this.changeParentPars()}>改變父層級的值</button>
</Col>
</Row>
)
}
用props這種方法調用的時候,如果傳遞的props是同一個引用對象,那麼只改變父級的state,傳遞給子集的props也會隨之改變,但如果是獨立引用對象,就需要在子集用componentWillReceiveProps監聽屬性值的變化,並隨之setState。
componentWillReceiveProps = (nextProps) =>{
console.log(nextProps)
this.setState(nextProps);
};
2.父級調用子組件的數據和方法
和上面的例子一樣,給組件childComponent加上一個ref屬性,相當於dom id,父級組件中調用this.refs.child1.state即可獲取子組件中的數據,調用this.refs.child1.innerMethod(pars)即調用子組件的方法
3.路由
在react中,一切都是組件,路由的話其實就是一個子組件,但要注意的是,用browserHistory.push(path);觸發路由的時候,如果立即調用this.refs.childPage去獲取子組件的話,獲取到的是路由變化前的,這裏需要等路由加載完成後再調用,我翻了半天router的api也沒找到路由完成後的回調,只能用setTimeout 1ms後,再調用就ok了。
class View extends Component {
componentDidMount = () => {
};
tabChange = (key) => {
// console.log(key);
let mySelf = this;
let uid = mySelf.state.uidFromUrl;
let uidFormat = (uid)?'?uid=' + uid:'';
let path = '/operation/personal/' + key + uidFormat;
// console.log(path)
browserHistory.push(path);
//等1ms路由切換完成後,再觸發子頁面的查詢
setTimeout(function(){
mySelf.triggerChildPageQuery();
},1);
};
triggerChildPageQuery = () => {
let mySelf = this;
let uid = mySelf.state.currentOption.key;
mySelf.refs.childPage.setUidFromParent(uid);
mySelf.hideLoading();
};
render() {
return (
<Spin tip="Loading..." spinning={loading} size="large">
{mySelf.props.children && React.cloneElement(mySelf.props.children, {
hideLoading: mySelf.hideLoading,
ref: "childPage",
})}
</Spin>
)
}
}
4.祖先傳參
業務場景是這樣的,路由子頁面需要設置祖先頁面的currentMenu,以達到切換tab的同時,高亮當前菜單的效果,由於路由的層級可能是很多層,如果逐層地父子通信,會很複雜,我這邊是用prop-types實現的。
具體實現,首先需要安裝一個名叫'prop-types'的庫,在父級菜單使用getChildText方法,來給子context對象的屬性賦值,子集中用mySelf.context來直接調用祖先的函數即可。
父級:
import PropTypes from 'prop-types';
class FrameWork extends Component {
componentDidMount = () =>{
};
getChildContext(){
return {
updateCrumbs: this.updateCrumbs(),
crumbPars: this.state.crumbPars,
updateMenu:this.onChangeMenu(),
}
};
onChangeMenu = (key) => {
// let mySelf = this;
return (key) => {
this.setState({currentMenu:key})
}
};
render() {
blabla....
}
}
//定義了頂層組件所擁有的子類context對象——該頂層組件所擁有的的子類context對象爲color,且必須爲字符串。
FrameWork.childContextTypes = {
crumbPars: PropTypes.any,
updateCrumbs: PropTypes.any,
updateMenu: PropTypes.any,
};
export default FrameWork;
子:
class View extends Component {
componentDidMount = () => {
this.initTab();
};
initTab = () => {
let mySelf = this;
mySelf.context.updateMenu("operationEnterprise");
};
}
View.contextTypes = {
updateMenu: PropTypes.any
};
export default View;