組件之間的通訊

在開發(fā)項目的時候 我們基本上是按照模塊組件來劃分的 也就是一個個模塊單獨開發(fā)然后再合并 最后打包成為一個獨立的作品。既然一個項目里面包含N個組件 那么這些組件是如何互通數(shù)據(jù)呢?
其實這個很簡單this.props嘛 搞定。。是的 這確實可以搞定 但只能說是搞定部分情況 別忘了這種方法只適于父子級關(guān)系 如果兩個不相干的組件呢 沒有任何繼承關(guān)系的呢 這就頭痛了
說到這里我們也不妨來看看一般情況下父子級關(guān)系的組件是如何通訊的

父-子

//  A(父級組件):
render(){
  return(
    <View>
      <B value={this.props.value}></B>
    </View>
  )
};

子-父

//  A(父級組件):
changeValue(flag){
  console.log(flag);  //true
};
render(){
  return(
    <View>
      <B callback={this.changeValue}></B>
    </View>
  )
};

//  B(子級組件):
press(){
  this.props.callback(true)
};
render(){
  return(
    <View onPress={this.press}></View>
  )
};

上面代碼就是常見的 有"關(guān)系"組件之間的通訊了 主要是通過this.propscallback的方式來實現(xiàn)的
那如何實現(xiàn)那些沒有關(guān)系組件之間的通訊呢 這就是下面要講的內(nèi)容了
利用自定義事件機制來通訊?

步入正題

為了更好的理解事件的通訊機制 讓我來舉個栗子 看圖

這個結(jié)構(gòu)圖很簡單 一看就懂 但是還是讓我在這里啰嗦一下
主要的思想: ManagerEvent作為一個中介 任何要通訊的組件都先和它來通訊 然后再由ManagerEvent去和你想要"發(fā)生關(guān)系"的組件去通訊。

上代碼先:managerEvent.js

var ManagerEvent = function() {
    this.handlers = {};
    this.BROADCAST = "broadcast";
}
ManagerEvent.prototype = {
    constructor: ManagerEvent,
    addEvent: function(handler) {
        if (typeof this.handlers[ManagerEvent.BROADCAST] == "undefined") {
            this.handlers[ManagerEvent.BROADCAST] = [];
        }
        this.handlers[ManagerEvent.BROADCAST].push(handler);
    },
    dispatchEvent: function(event) {
        if (!event.target) {
            event.target = this;
        }
        if (this.handlers[event.type] instanceof Array) {
            var handlers = this.handlers[event.type];
            for (var i = 0, len = handlers.length; i < len; i++) {
                handlers[i](event);
            }
        }
    },
    removeEvent: function(type, handler) {
        if (this.handlers[type] instanceof Array) {
            var handlers = this.handlers[type];
            for (var i = 0, len = handlers.length; i < len; i++) {
                if (handlers[i] === handler) {
                    break;
                }
            }
            handlers.splice(i, 1);
        }
    }
}
module.exports = new ManagerEvent();

使用

step1:在你需要通訊的模塊里引用 如:import OS from 'ManagerEvent';
step2:

如果當前模塊需要去影響其他模塊 用dispatchEvent

OS.dispatchEvent({
  action:'XXX_XXX_XXX',  //動作類型 (找誰通訊)
  data:{                 //動作參數(shù) (告訴它這個是數(shù)據(jù))
    id:2,
    name:'zkey'
  }
});
//提醒:在模塊里任何一個地方都可以調(diào)用dispatchEvent來發(fā)送事件

如果當前模塊需要被其他模塊影響 比如當前模塊想關(guān)心XXX_XXX_XXX類型的事件 只需在模塊當中 用 addEvent來監(jiān)聽就可以

OS.addEvent(function(e){
  if(e.action === 'XXX_XXX_XXX'){
    console.log(e.data);  //{id:2,name:'zkey'}
  }
})
//提醒:代碼一般放在模塊構(gòu)造函數(shù)里 初始化就讓執(zhí)行

為了更好的管理action 我這里通常的做法會把所有action都統(tǒng)一放在一個模塊里 然后誰用誰來調(diào) 這樣:action.js

module.exports = {
  SWITCH_TAB:'切換路由',
  API_LOAD_SUCCESS:'數(shù)據(jù)加載完成',
  ....
}

簡單的示例

A模塊Amod.js

import React from 'react';
import {
  Text,
  View
} from 'react-native';
//引入事件管理模塊
import OS from 'managerEvent';
//引入事件類型(動作)
import ACT from 'action';

export default class Amod extends React.Component {
  constructor(props) {
    super(props);
  }

  sendInfo(){
    OS.dispatchEvent({
      action:ACT.GET_INFO,
      data:{name:'zkey',age:'30','type':'帥'}
    })
  }

  render() {
    return (
        <View>
            <Text onPress={this.sendInfo}>點擊把數(shù)據(jù)給到Bmod里</Text>
        </View>
    );
  }
}

B模塊 Bmod.js

import React from 'react';
import {
  Text,
  View
} from 'react-native';
//引入事件管理模塊
import OS from 'managerEvent';
//引入事件類型(動作)
import ACT from 'action';

export default class Bmod extends React.Component {
  constructor(props) {
    super(props);

    this.init();
  }

  init(){
    OS.addEvent(function(e){
      if(e.action === ACT.GET_INFO){
        console.log(e.data);  //{name:'zkey',age:'30','type':'帥'}
      }
    })
  }
}

action.js

module.exports = {
    GET_INFO:'獲取信息',
}

總結(jié)

1.當任何模塊之間需要通訊的時候 首先在action.js創(chuàng)建一個動作標示 然后在需要發(fā)出動作的地方調(diào)用dispatchEvent發(fā)送你的需求到managerEvent.js里 然后由managerEvent通知項目里所有監(jiān)聽的模塊 最后各個模塊通過if(e.action === ACT.XXX_XXX_XXX)的方式來判斷該通知是否與我有關(guān) 如果是我關(guān)注的通知 我就做相應(yīng)更新 通過e.data來獲取更新數(shù)據(jù) 反之則什么都不做。
2.一個模塊里面可以監(jiān)聽多個事件動作如

OS.addEvent(function(e){
  if(e.action === ACT.GET_INFO){
    //...
  }
  if(e.action === ACT.LOAD_SUCCESS){
    //...
  }
})

3.同一個模塊里可以是發(fā)送事件也可以監(jiān)聽事件
4.發(fā)送事件的時候可以帶data或者不帶
5.參與通訊的模塊要確保已經(jīng)被渲染完成

下面是managerEvent來做的一個 路由和導航之間的互相同步例子(圖片)

ccc.gif
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容