在開發(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.props 和 callback的方式來實現(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來做的一個 路由和導航之間的互相同步例子(圖片)
