React兄弟、父子元素之间的通信
React元素之间的通信主要由下面几种方式
1、 Redux
2、 EventEmitter
3、 通过props进行通信(需要有嵌套关系)
子元素到父元素
父子元素之间的通信主要靠props
,这个方法既简单,又好用,所以可以使用这种方法的时候就直接用好了。
首先有这样的一个React DOM结构:
<div className="passage">
<NavBar />
<Passage />
</div>
渲染外层的div
元素的时候,需要进行两个子组件的渲染,其中Passage
组件的加载内容取决于NavBar
当前的内容或者被点击后的内容,这里可以首先实现父元素和NavBar
之间的通信过程,设置一个句柄,来帮助进行通信。
constructor (props) {
super(props);
this.state = {
currentPassage: ""
}
this.refreshCurrentPassage = this.refreshCurrentPassage.bind(this);
}
refreshCurrentPassage(cp) {
this.setState({
currentPassage: cp
});
}
上面的refreshCurrentPassage
函数是这个通信过程的关键,我们将这个函数绑定当前父元素的this
对象,并且将这个函数通过props
传递给子元素:
render() {
return (
<div className="passage">
<NavBar refreshCurrentPassage={this.refreshCurrentPassage} />
<Passage currentPassage={this.state.currentPassage}/>
</div>
);
}
子元素在其生命周期的componentDidMount
阶段通过ajax获取当前页信息并且调用这个函数,将消息传递给父元素,这里需要注意React的生命周期,componentDidMount
在官方给出的解释是:
Invoked once, only on the client (not on the server), immediately after the initial rendering occurs.
注意是在初始化渲染之后执行一次的。如果你还有其他特殊需求的话可以在其他阶段来调用这个函数。
class NavUl extends React.Component {
constructor (props) {
super(props);
this.state = {
passage: []
}
}
componentDidMount() {
//在ajax请求成功之后调用一次更新父元素状态的函数,来完成一次父子元素之间的通信
$.ajax({
url: "../resources/data/passage.json",
success: (data) => {
this.setState({
passage: data.passages
});
this.props.refreshCurrentPassage(data.passages[0].passageName);
}、
});
}
render() {
let liArray = [];
this.state.passage.forEach((value,index) => {
let liEle = <li key={value.passageName.toString()}>
<a>
{value.passageName}({value.letterNum}) author:{value.author}
</a>
</li>
liArray.push(liEle);
});
return (
<ul>
{liArray}
</ul>
)
}
}
class NavBar extends React.Component {
constructor (props) {
super(props);
}
render() {
return (
<nav>
<NavUl refreshCurrentPassage={this.props.refreshCurrentPassage}/>
</nav>
);
}
}
父元素到子元素
父元素到子元素的状态通信更加简单了,可以直接使用props
来进行传递。
//父元素的render函数
render() {
return (
<div className="passage">
<NavBar refreshCurrentPassage={this.refreshCurrentPassage} />
<Passage currentPassage={this.state.currentPassage}/>
</div>
);
}
通过将自己的state的currentPassage属性传递给子元素的一个属性,也就是props
对象,来告诉子元素加载某个模块。
class Passage extends React.Component {
constructor (props) {
super(props);
this.state = {
passage: ""
}
}
//子元素通过自己的this.props对象来进行访问,可以直接得到父元素传递的消息
componentWillReceiveProps (nextProps) {
let passageName = nextProps.currentPassage;
passageName = passageName.toLowerCase().replace(" ", "");
$.ajax({
url: "../resources/data/" + passageName + ".json",
success: (data) => {
this.setState({
passage: data.passageContent
});
}
});
}
render() {
return (
<article>
<p>
{this.state.passage}
</p>
</article>
);
}
}
兄弟元素之间
上面的两个部分组合起来刚好就完成了兄弟元素之前的通信,其中一个子元素通过调用父元素传递过来的函数this.props.refreshCurrentPassage
来修改父元素状态,然后在父元素状态修改之后,另外一个子元素的this.props
会发生变化,从而触发重新渲染。这里需要注意的是React组件的声明周期,父元素到子元素通信由于可能需要多次渲染,所以使用了声明周期中的componentWillReceiveProps
阶段来进行内容加载。在官方文档中是这么介绍这个阶段的:
Invoked when a component is receiving new props. This method is not called for the initial render.
也就是在一个组件接收了新的属性(props
)触发的,这个方法不会在初始化渲染的时候触发。并且这个阶段还可以访问修改前的props
对象。
来源:oschina
链接:https://my.oschina.net/u/4349592/blog/3956482