组件之间进行通信的情况:
父组件向子组件通信
子组件向父组件通信
兄弟组件之间通信
发布者-订阅者模式
一、父组件向子组件通信
React数据流动是单向的,数据必须从一方传到另一方。在react中,父组件可以通过向子组件传递props,完成父子组件通信。
class Parent extends Components{
this.state={
message: 'hello'
};
componentDidMount(){
setTimeout(()=>{
this.setState({
message: 'world'
});
},2000);
}
render(){
return
}
}
class Child extends Component{
render(){
return
}
}
如果父与子之间不止一个层级,如祖孙关系,可以通过...(es6运算符)将父组件的信息,以更简洁的方式传递给更深层级的子组件。而且这种方式不用考虑性能问题,通过babel转义后的...性能与原生一致,且上级组件props和state改变,会导致组件本身和其子组件的生命周期改变。
二、子组件向父组件通信
子组件向父组件通信,也需要父组件向子组件传递props,只是父组件传递的,是作用域为父组件自身的函数,子组件调用该函数,将子组件想要传递的信息,作为参数,传递到父组件的作用域中。
class Parent extends Component{
this.state = {
message: 'hello'
};
transferMsg(msg){
this.setState({
message
});
}
render(){
return
child msg: {this.state.message}
}
}
class Child extends Component{
componentDidMount(){
setTimeOut( () => {
this.props.transferMsg('world')
},2000)
}
render(){
return
}
}
上面的例子中,将父组件的 transferMsg 函数通过props传递给子组件,得益于箭头函数,保证了子组件在调用transferMsg 函数时,其内部的this仍指向父组件。
三、兄弟组件之间通信
对于没有直接关联联系的两个节点,总也能找到它们共同的父组件,如果这两个节点child1,child2要通信,可以先通过child1向父组件通信,再由父组件向child2通信。
class Parent extends Component{
this.state = {
msg: 'hello'
};
transferMsg(msg) {
this.setState({
msg
});
}
componentDidUpdate(){
console.log('Parent update');
}
render() {
return(
);
}
}
class Child_1 extends Component{
componentDidMount() {
setTimeout(() => {
this.props.transferMsg('world')
}, 2000);
}
componentDidUpdate() {
console.log('Child_1 update');
}
render() {
return
child_1 component
}
class Child_2 extends Component{
componentDidUpdate() {
console.log('Child_2 update');
}
render() {
return
child_2 component: {this.props.msg}
}
}
}
除了层层组件传递props,也可以使用context。context是一个全局变量,像是一个大容器,在任何地方都可以访问到,我们可以把要通信的信息放在context上,然后在其他组件中可以随意取到。但是React官方不建议使用大量context,尽管他可以减少逐层传递,但是当组件结构复杂的时候,我们并不知道context是从哪里传过来的,而且context是一个全局变量,全局变量是导致应用走向混乱的罪魁祸首。
四、发布者-订阅者模式
发布者-订阅者模式也叫观察者模式,大量使用在各类框架类库的设计中。发布者发布事件,订阅者监听事件并作出反应,对于上面的代码,我们可以引入一小个模块,使用观察者模式进行改造。在componentDidMount事件中,如果组件挂载完成,订阅事件;在组件卸载的时候,在componentwillUnmount事件中取消对事件的订阅。
import eventProxy from '../eventProxy'
class Parant extends Component{
render(){
return(
)
}
}
//componentDidUpdate、render方法与上例一致
class Child_1 extends Component{
componentDidMount(){
setTimeOut(()=>{
//发布msg事件
eventProxy.trigger('msg','end')
},1000)
}
}
//componentDidUpdate方法与上例一致
class Child_2 extends Component{
state={
msg:'start'
}
componentDidMount(){
//监听msg事件
eventProxy.on('msg',(msg)=>{
this.setState({
msg
})
})
}
render(){
return
child_2 component: {this.state.msg}
}
}
我们在child_2组件的componentDidMount中订阅了msg事件,并在child_1的componentDidMount中,在1s后发布了msg事件,child_2组件对msg事件做出响应,更新了自身的state,在整个通讯过程中,只改变了child_2的state,因此只有child_2和child_2_1的生命周期被触发。
而上述eventProxy中,总共有on、one、off、trigger这四个函数:
on、one:on与one函数用于订阅者监听相应的事件,并将事件响应时的函数作为参数,on与one的唯一区别就是,使用one进行订阅的函数,只会触发一次,而使用on进行订阅的函数,每次事件发生相应时都会被触发。
trigger:trigger用于发布者发布事件,将除第一参数(事件名)的其他参数,作为新的参数,触发使用one与on进行订阅的函数。
off:用于解除订阅了某个事件的所有函数。