React 组件间通讯

2,220 阅读2分钟

React 组件通信包含一下 4 种情况:

  1. 父子组件通信
  2. 子父组件通信
  3. 跨级组件通信
  4. 无嵌套组件通信

父组件向子组件或者子组件向父组件通信的方式这里没做阐述,这里主要记录跨组件通信和无嵌套组件间通信。

理论东西没做太多记录(可以留言,我做补充),主要是想给出最小的实现,让初学者从代码层面快速理解和使用:

  • 跨组件通信

    实现跨组件通信常用的两种方式(当然不包括 Flux、Redux 这种方式):

    1. 通过 props 实现跨组件通信,即通过 props 父传子 —> 子又传子 来实现。 这种方式有个明显的缺点就是组件层级太深时候,造成数据的混乱,不易维护。
    2. 通过 context 对象实现跨组件通信,参考 demo: github.com/wewin11235/…,可以将 context 理解成一个全局变量

    实现过程:

    • 父组件首先声明自己可以支持 context,定义 childContextTypes 方法。
    • 父组件需要定义方法,返回 context 对象,定义 getChildContext 方法。
    • 子组间声明自己需要使用 context,定义 contextTypes 方法。
  • 无嵌套组件之间的通信有两种方式:(不包括 Flux、Redux 这种方式)

    1. 定义组件共同的父组件,然后通过父组件实现相互通信

      这种做法在项目稍复杂时就会有数据混乱,难以维护的问题。

    2. 通过可以影响全局的一些机制去实现。

      自定义事件机制,就是一种上佳的实现方案。使用 Node.js Events 模块的浏览器版实现来进行事件的发布/订阅。

      这里主要是要理解 event 事件机制,参考链接, 理解了 event, 这种通通信方式就很容易明白。

      下面给个最简单 demo: 在组件 <List2> 中点击按钮,让 <List1> 中数字加一。<List1> 中进行事件发布,<List2> 中订阅该事件。

      为了看起来直观,组件没有分开到不同文件,demo 核心代码如下:

      import React from 'react';
      import { EventEmitter } from 'events';  // 这里在 React 15.2 以上,需要安装 events: ```npm install events``` 即可。
      
      // 初始化 EventEmitter 实例
      const emitter = new EventEmitter();
      
      // List1 组件,发布事件
      class List1 extends React.Component {
        constructor(props) {
          super(props);
          this.state = {
           count: 0
          }
        }
      
        componentDidMount() {
          const listener = () => {
            this.setState({
              count: this.state.count + 1
            });
          }
      
        this.eventEmitter = emitter.on('incream', listener); // EventEmitter 的实例方法 'on' 用于注册一个事件
      }
      
       componentWillUnmount() {
          emitter.removeListener(this.eventEmitter);  // 在组件卸载时候,需要移除该事件
       }
      
       render(){
         return(
           <div>
             {this.state.count}
           </div>
         );
       }
      }
      
      class List2 extends React.Component {
        constructor(props) {
          super(props);
        }
      
       onHandleIncream() {
         emitter.emit('incream'); // ventEmitter 的实例方法 'emit' 用于执行注册到 'incream' 上的方法
       }
      
       render() {
         return(
           <div>
             <button onClick={this.onHandleIncream.bind(this)}>incream</button>
           </div>
         );
       }
      }
      
      ReactDOM.render(
       <div>
         <List1 />
         <List2 />
       </div>,
        document.getElementById('root');
      );
      
      

    暂时记录到这里,还有很多细节,后面补充。