当前位置 博文首页 > wengqt的博客:React组件通信——Event Bus

    wengqt的博客:React组件通信——Event Bus

    作者:[db:作者] 时间:2021-06-12 09:37

    使用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 Bus

    我们可以通过对event的订阅和发布来进行通信,这里举一个栗子:A和B是两个互不相关的组件,A组件的功能是登录,B组件的功能是登录之后显示用户名,这里就需要A组件将用户名传递给B组件。那么我们应该怎么做呢?

    • 在A组件中注册/发布一个type为login的事件;
    • 在B组件中注册一个监听/订阅,监听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 实现了跨组件的通信。