組件之間的通訊

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

父-子

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

子-父

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

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

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

步入正題

為了更好的理解事件的通訊機(jī)制 讓我來(lái)舉個(gè)栗子 看圖

這個(gè)結(jié)構(gòu)圖很簡(jiǎn)單 一看就懂 但是還是讓我在這里啰嗦一下
主要的思想: ManagerEvent作為一個(gè)中介 任何要通訊的組件都先和它來(lái)通訊 然后再由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:

如果當(dāng)前模塊需要去影響其他模塊 用dispatchEvent

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

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

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

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

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

簡(jiǎn)單的示例

A模塊Amod.js

import React from 'react';
import {
  Text,
  View
} from 'react-native';
//引入事件管理模塊
import OS from 'managerEvent';
//引入事件類(lèi)型(動(dòng)作)
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}>點(diǎn)擊把數(shù)據(jù)給到Bmod里</Text>
        </View>
    );
  }
}

B模塊 Bmod.js

import React from 'react';
import {
  Text,
  View
} from 'react-native';
//引入事件管理模塊
import OS from 'managerEvent';
//引入事件類(lèi)型(動(dòng)作)
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.當(dāng)任何模塊之間需要通訊的時(shí)候 首先在action.js創(chuàng)建一個(gè)動(dòng)作標(biāo)示 然后在需要發(fā)出動(dòng)作的地方調(diào)用dispatchEvent發(fā)送你的需求到managerEvent.js里 然后由managerEvent通知項(xiàng)目里所有監(jiān)聽(tīng)的模塊 最后各個(gè)模塊通過(guò)if(e.action === ACT.XXX_XXX_XXX)的方式來(lái)判斷該通知是否與我有關(guān) 如果是我關(guān)注的通知 我就做相應(yīng)更新 通過(guò)e.data來(lái)獲取更新數(shù)據(jù) 反之則什么都不做。
2.一個(gè)模塊里面可以監(jiān)聽(tīng)多個(gè)事件動(dòng)作如

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

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

下面是managerEvent來(lái)做的一個(gè) 路由和導(dǎo)航之間的互相同步例子(圖片)

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

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

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