React组件间通信(事件总线)的小例子

3,340 阅读2分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战」。

关于 React 的组件间通讯,网上有很多组件间通讯的文章。

父子组件间直接传事件,然后提升处理就可以。
父子孙曾孙之类的,也可以把事件一层层地传进去,这样虽然繁琐,但是感觉结构清晰。
再就是事件总线(Event Bus)的方式。
无直接关系相对独立的组件间,只能采用事件总线的方式。
事件总线,感觉就是针对全局的事件监听和事件触发。

事件总线这个,本来是一个很简单的技术点。
为了下次遇到同样的问题减少搜索,还是自己整理了一个小例子。


在组件1中注册事件总线,在组件2中触发事件,组件1监听到事件被触发后作出响应处理。

相关代码:helloreact/eventbus at main · bettersun/helloreact · GitHub

  1. create-react-app 创建 React 工程。

    npx create-react-app eventbus
    
  2. 事件总线相关的 js。

    event.js

     ```javascript
     import { EventEmitter } from 'events';
    
     // new一个全局的EventEmitter对象
     const eventEmiter = new EventEmitter();
    
     // 组件间通讯的事件
     const eventHello = "hello";
    
     // 注册事件监听
     export function addListenerHello(handler) {
         eventEmiter.on(eventHello, handler);
     }
    
     // 触发事件
     export function doHello(args) {
         eventEmiter.emit(eventHello, args);
     }
     ```
    

    导入 events 里的 EventEmitter。
    在 event.js 里创建一个全局的 EventEmitter 对象。
    定义(触发和监听的)事件名称,然后定义一个用来注册事件监听的函数和一个触发事件的函数。

  3. 组件1

    import { useState, useEffect } from "react";
    import { addListenerHello } from './event';
    
    function HelloOne() {
    
        const [message, setMessage] = useState("Hello");
    
        useEffect(
            () => {
                // 注册事件监听,把事件触发时要调用的处理函数传递过去。
                // 运行一次即可
                addListenerHello(helloHandler);
            }, []
        )
    
        // 组件间通讯事件触发时的处理。
        function helloHandler(args) {
            setMessage("Hello, " + args + "!")
        }
    
        return (
            <div>
                {message}
            </div>
        );
    }
    
    export default HelloOne;
    

    注册事件监听,把事件触发时要调用的处理函数传递过去。
    运行一次即可。

  4. 组件2

    import { useState } from "react";
    import { doHello } from './event';
    
    function HelloTwo() {
        const [message, setMessage] = useState("");
    
        function hello() {
            // 触发组件间通讯的事件,传递参数。
            doHello("world");
    
            setMessage("I said hello.");
        }
    
        return (
            <div>
                <button onClick={hello}>say hello</button>
                <br />
                {message}
            </div>
        );
    }sd
    
    export default HelloTwo;
    

    组件2中的动作触发事件,组件1会监听到事件的触发后进行对应的处理。

  5. App.js

    import HelloOne from './HelloOne';
    import HelloTwo from './HelloTwo';
    
    import './App.css';
    
    function App() {
    
      return (
        <div className="App">
          <div className={'column1'}>
            <HelloOne></HelloOne>
          </div>
          <div className={'column2'}>
            <HelloTwo></HelloTwo>
          </div>
        </div>
      );
    }
    
    export default App;
    

    App.js 中放置组件1和组件2,二者相对独立。

  6. 效果:

    eventbus.gif