由iOS原生開(kāi)發(fā)轉(zhuǎn)到React Native開(kāi)發(fā)茄螃,再接著慢慢開(kāi)始學(xué)習(xí)前端開(kāi)發(fā)壳咕,真心覺(jué)得搞技術(shù)太難了這句話太正確了。當(dāng)前正在開(kāi)發(fā)的項(xiàng)目中使用了Vue+Vuex+Electron來(lái)實(shí)現(xiàn)桌面應(yīng)用開(kāi)發(fā)补箍,在學(xué)習(xí)了Vuex之后匾七,決定對(duì)之前學(xué)的各種數(shù)據(jù)流管理架構(gòu)做一個(gè)系統(tǒng)的總結(jié),所以接下來(lái)我還會(huì)總結(jié)
數(shù)據(jù)流架構(gòu)學(xué)習(xí)筆記(二)-Redux
數(shù)據(jù)流架構(gòu)學(xué)習(xí)筆記(三)-Vuex
數(shù)據(jù)流架構(gòu)學(xué)習(xí)筆記(一)-Flux 是這次系統(tǒng)總結(jié)的第一篇筆記囚玫,都是一些自己的學(xué)習(xí)和總結(jié)喧锦,權(quán)當(dāng)學(xué)習(xí)參考。
Flux是什么抓督?
Flux是Facebook官方提出一種架構(gòu)思想燃少,他的出現(xiàn)同樣也是為了解決實(shí)際項(xiàng)目中軟件結(jié)構(gòu)的問(wèn)題,如果你了解過(guò)MVC铃在,MVVM之類的東西阵具,其實(shí)就應(yīng)該知道這是一樣的東西,他們是一種思想定铜,為了讓你的應(yīng)用能夠更加合理的工作和運(yùn)行阳液,具體到如何應(yīng)用在你的項(xiàng)目中,通過(guò)代碼和一些工具可以仁者見(jiàn)仁揣炕、智者見(jiàn)智的使用帘皿。
Flux如何工作
一個(gè) Flux 應(yīng)用主要包含四個(gè)部分:
-
the dispatcher
: 處理動(dòng)作分發(fā),并且向注冊(cè)的回調(diào)函數(shù)廣播payloads畸陡,維護(hù) Store 之間的依賴關(guān)系 -
the stores
: 應(yīng)用程序狀態(tài)的容器鹰溜,并且含有注冊(cè)到Dispatcher的回調(diào)函數(shù),數(shù)據(jù)和邏輯部分 -
the views
: 視圖組件丁恭,這一層可以看作controller-views曹动,作為視圖同時(shí)響應(yīng)用戶交互 -
the actions
: 提供通過(guò)具體行為使用dispatcher 傳遞數(shù)據(jù)給 store,是一些使用Dispatcher傳遞數(shù)據(jù)的具體方法集合
Flux 的核心單向數(shù)據(jù)流
是這樣運(yùn)作的:
View -> Action -> Dispatcher -> Store -> View
更多時(shí)候 View 會(huì)通過(guò)用戶交互觸發(fā) Action牲览,所以一個(gè)簡(jiǎn)單完整的數(shù)據(jù)流類似這樣:
假設(shè)現(xiàn)在在項(xiàng)目中墓陈,Action模塊、Stroe模塊、View模塊等都已建立成功贡必,Dispatcher來(lái)自官方Flux庫(kù)熬的,以從頁(yè)面登錄的例子進(jìn)行一次Flux流程說(shuō)明,流程如下:
- 頁(yè)面點(diǎn)擊登錄按鈕赊级,View觸發(fā)點(diǎn)擊動(dòng)作押框,調(diào)用Action中的網(wǎng)絡(luò)請(qǐng)求封裝函數(shù);
- Action調(diào)用網(wǎng)絡(luò)庫(kù)相關(guān)API理逊,并成功返回用戶登錄成功參數(shù)橡伞,或返回失敗錯(cuò)誤。
- 在成功返回的callback中通過(guò)Dispatcher分發(fā)用戶信息Payload至Store更改數(shù)據(jù)并存儲(chǔ)新數(shù)據(jù)中晋被。
- store通過(guò)前期已注冊(cè)的對(duì)應(yīng)通知及emit()將最新的數(shù)據(jù)分發(fā)出去兑徘,頁(yè)面監(jiān)聽(tīng)到數(shù)據(jù)變化,從而更新頁(yè)面數(shù)據(jù)羡洛,重新渲染頁(yè)面挂脑。
實(shí)例應(yīng)用
因?yàn)楣ぷ髌騌eact Native,這里以登錄流程中部分React Native代碼展示如何將Flux應(yīng)用到React Native開(kāi)發(fā)中進(jìn)行數(shù)據(jù)管理,(由于代碼時(shí)間較久欲侮,存在一些不合理之處請(qǐng)忽略崭闲,但不影響Flux數(shù)據(jù)流的理解):
視圖層View:
登錄頁(yè):
...
_login(userName, passWord) {
LoginActions.login({
username: userName,
password: passWord,
...
}, (response) => {
this.props.navigator.resetTo({comp:MainContainer});
}, (error) => {
Alert.alert(
'提示',
'error',
[{ text: '確定' }]
);
});
}
...
主頁(yè):
class Main extends Component{
constructor(props){
super(props);
this.state = {
user: AppStore.getUser(),
...
};
}
componentDidMount() {
AppStore.addChangeListener(this._userStateChange, 'USER_CHANGE');
}
componentWillUnmount() {
AppStore.removeChangeListener(this._userStateChange, 'USER_CHANGE');
}
_onChange: function () {
this.setState({
user: AppStore.getUser()
});
},
...
...
}
登錄頁(yè)是你的點(diǎn)擊交互事件,你通過(guò)點(diǎn)擊觸發(fā)登錄調(diào)用Action威蕉,主頁(yè)Main會(huì)存在登錄后返回的用戶信息刁俭,數(shù)據(jù)來(lái)源于你的數(shù)據(jù)倉(cāng)庫(kù)AppStore,頁(yè)面當(dāng)然還存在頁(yè)面監(jiān)聽(tīng)者韧涨,知道當(dāng)你的數(shù)據(jù)改變的時(shí)候牍戚,知道該如何去更新你的頁(yè)面。
行為Action:
...
const _login = (params, callback, failure) => {
const requestUrl = CommonLink.login(params.username, params.password);
return Fetcher.getFetch(requestUrl)
.then((response) => {
AppDispatcher.dispatch({
actionType: AppConstants.LOGIN,
data: response.body,
});
callback(response);
}).catch((error) => {
failure(error);
});
};
...
module.exports = {
login: (params, callback, failure) => _login(params, callback, failure),
...
}
觸發(fā)一個(gè)行為調(diào)用Action方法進(jìn)行了網(wǎng)絡(luò)API的調(diào)用虑粥,進(jìn)行登錄如孝,并返回成功用戶信息后,通過(guò)Dispatcher將數(shù)據(jù)和消息分發(fā)出去娩贷,把接下來(lái)的工作交給數(shù)據(jù)倉(cāng)庫(kù)Store第晰。
數(shù)據(jù)倉(cāng)庫(kù)Stores:
const dataStore = {
user: {},
...
}
const AppStore = _.assign({}, EventEmitter.prototype, EventEmitter.prototype._maxListeners = 30, {
emitChange(event = 'DEFAULT_EVENT') {
this.emit(event);
},
addChangeListener(callback, event = 'DEFAULT_EVENT') {
this.on(event, callback);
},
removeChangeListener(callback, event = 'DEFAULT_EVENT') {
this.removeListener(event, callback);
},
...
getUser: () => dataStore.user || {},
...
});
...
// Register callback to handle all updates
AppDispatcher.register((action) => {
switch (action.actionType) {
...
case AppConstants.LOGIN:
_.assign(dataStore, {
username: action.data.user.username,
...
});
AppStore.emitChange('USER_CHANGE');
break;
...
}
});
module.exports = AppStore;
在數(shù)據(jù)倉(cāng)庫(kù)中,你應(yīng)該定義出倉(cāng)庫(kù)對(duì)象AppStore育勺,并對(duì)AppDispatcher注冊(cè)入各種操作但荤,即當(dāng)接收到AppDispatcher發(fā)來(lái)的不同消息時(shí),操作數(shù)據(jù)并保存數(shù)據(jù)到dataStore中涧至,之后通過(guò)AppStore.emit()將更新通知發(fā)送到頁(yè)面中,讓頁(yè)面進(jìn)行重新渲染桑包。從而完成整個(gè)Flux數(shù)據(jù)流的閉環(huán)南蓬。
關(guān)于AppDispatcher和AppConstants
上述代碼中用到的AppDispatcher和AppConstants代碼如下:
AppDispatcher:
import {Dispatcher} from 'flux'
module.exports = new Dispatcher();
AppConstants:
const keyMirror = require('keymirror');
const AppConstants = keyMirror({
...
LOGIN: null,
...
});
module.exports = AppConstants;
可以看出這些只是為了更好的使用Flux而引入庫(kù)和輔助工具,你也可以使用其他類似工具。
總結(jié)
Flux學(xué)習(xí)和理解需要的是在項(xiàng)目中實(shí)際應(yīng)用進(jìn)去赘方,同樣只要理解了單向數(shù)據(jù)流的思想烧颖,理解Flux也是很快的,F(xiàn)lux是單向數(shù)據(jù)流的一種具體架構(gòu)實(shí)現(xiàn)窄陡。接下來(lái)會(huì)再總結(jié)關(guān)于Redux的理解和使用炕淮,同樣也是單向數(shù)據(jù)流的一種具體實(shí)現(xiàn),基于Flux跳夭,但是比Flux更加方便和強(qiáng)大涂圆。而當(dāng)前的很多React開(kāi)發(fā)項(xiàng)目也都基于使用Redux。
雖然搞技術(shù)很難币叹,但是做自己喜歡的事情還是很開(kāi)心的润歉,一起學(xué)習(xí),努力奮斗颈抚。