当前位置 博文首页 > wengqt的博客:React组件通信——Event Bus
首先,我们来回顾一下React中组件通信的方式:
父子组件之间的通信,一般是通过props来
简单来说,就是通过一个将需要通信的变量a定义在父组件中,然后通过props来传递给子组件,如果子组件要更改这个变量,那么父组件就需要定义setA方法,然后也通过props传递给子组件,这样就完成了父子组件之间的通信。
非父子组件之间的通信
如果两个组件离得近的话,我们可以在两个组件外层嵌套一个父组件,通过父组件共享变量进行通信。这样的话就可以采用上面那个方法来实现了。
下面是一个todo list的例子:
todo list包含一个输入组件和一个列表组件,这两个组件需要通信就需要在外层包裹一个TodoComponent,然后维护一个list列表,输入组件调用changeList方法添加事项,列表组件通过this.state.list的变化来重新渲染列表。
export default class TodoComponent extends React.Component{
constructor(props){
super(props);
this.state={
list:[]
};
}
changeList(last){
this.setState({
list: [...this.state.list, last]
})
}
handleRemove(index){
//console.log(this.state.list.splice(index,1));
this.state.list.splice(index,1);
this.setState({
list:this.state.list
})
}
render(){
return(
<div>
<Inputcomponent changeList={(last)=>this.changeList(last)} list={this.state.list}/>
<Listcomponent list={this.state.list} handleRemove={(index)=>this.handleRemove(index)}/>
</div>
)
}
}
那么,如果两个组件相隔很远,嵌套了很多组件,则无法采用上面的方法进行通信,这里就需要其他的方式进行通信。
- 如果项目复杂的话,采用redux、mobx进行全局的数据流管理
- 采用发布订阅的Event Bus来进行组件通信
我们可以通过对event的订阅和发布来进行通信,这里举一个栗子:A和B是两个互不相关的组件,A组件的功能是登录,B组件的功能是登录之后显示用户名,这里就需要A组件将用户名传递给B组件。那么我们应该怎么做呢?
注册/发布
一个type为login
的事件;监听/订阅
,监听login
事件的触发;login
事件触发,然后B组件就可以触发这个事件的回调函数。那么,我们要如何实现这个Event Bus呢?
class EventBus {
constructor() {
this.events = this.events || new Object();
}
}
//首先构造函数需要存储event事件,使用键值对存储
//然后我们需要发布事件,参数是事件的type和需要传递的参数
EventBus.prototype.emit = function(type, ...args) {
let e;
e = this.events[type];
// 查看这个type的event有多少个回调函数,如果有多个需要依次调用。
if (Array.isArray(e)) {
for (let i = 0; i < e.length; i++) {
e[i].apply(this, args);
}
} else {
e[0].apply(this, args);
}
};
//然后我们需要写监听函数,参数是事件type和触发时需要执行的回调函数
EventBus.prototype.addListener = function(type, fun) {
const e = this.events[type];
if (!e) { //如果从未注册过监听函数,则将函数放入数组存入对应的键名下
this.events[type]= [fun];
} else { //如果注册过,则直接放入
e.push(fun);
}
};
const eventBus = new EventBus();
export default eventBus;
到目前为止我们的Event Bus完成了。
然后,我们在login
组件中加入
EventBus.emit('login',values.userName)
在需要监听的组件加入
EventBus.addListener('login',(name)=>{
this.setState({user:name})
})
这样,登录的用户名就传递到当前组件了。
登录前:侧边栏上显示请登录。
登陆后:已经将用户名传递到侧边栏组件了。
就这样,我们简单的通过Event Bus 实现了跨组件的通信。