在開(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.props 和 callback的方式來(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)航之間的互相同步例子(圖片)
