由iOS原生開發轉到React Native開發,再接著慢慢開始學習前端開發,真心覺得搞技術太難了這句話太正確了。當前正在開發的專案中使用了Vue+Vuex+Electron來實現桌面應用開發,在學習了Vuex之後,決定對之前學的各種資料流管理架構做一個系統的總結,所以接下來我還會總結
資料流架構學習筆記(二)-Redux
資料流架構學習筆記(三)-Vuex
資料流架構學習筆記(一)-Flux 是這次系統總結的第一篇筆記,都是一些自己的學習和總結,權當學習參考。
Flux是什麼?
Flux是Facebook官方提出一種架構思想,他的出現同樣也是為了解決實際專案中軟體結構的問題,如果你瞭解過MVC,MVVM之類的東西,其實就應該知道這是一樣的東西,他們是一種思想,為了讓你的應用能夠更加合理的工作和執行,具體到如何應用在你的專案中,通過程式碼和一些工具可以仁者見仁、智者見智的使用。
Flux如何工作
一個 Flux 應用主要包含四個部分:
the dispatcher
: 處理動作分發,並且向註冊的回撥函式廣播payloads,維護 Store 之間的依賴關係the stores
: 應用程式狀態的容器,並且含有註冊到Dispatcher的回撥函式,資料和邏輯部分the views
: 檢視元件,這一層可以看作controller-views,作為檢視同時響應使用者互動the actions
: 提供通過具體行為使用dispatcher 傳遞資料給 store,是一些使用Dispatcher傳遞資料的具體方法集合
Flux 的核心單向資料流
是這樣運作的:
View -> Action -> Dispatcher -> Store -> View複製程式碼
更多時候 View 會通過使用者互動觸發 Action,所以一個簡單完整的資料流類似這樣:
假設現在在專案中,Action模組、Stroe模組、View模組等都已建立成功,Dispatcher來自官方Flux庫,以從頁面登入的例子進行一次Flux流程說明,流程如下:
- 頁面點選登入按鈕,View觸發點選動作,呼叫Action中的網路請求封裝函式;
- Action呼叫網路庫相關API,併成功返回使用者登入成功引數,或返回失敗錯誤。
- 在成功返回的callback中通過Dispatcher分發使用者資訊Payload至Store更改資料並儲存新資料中。
- store通過前期已註冊的對應通知及emit()將最新的資料分發出去,頁面監聽到資料變化,從而更新頁面資料,重新渲染頁面。
例項應用
因為工作偏向React Native,這裡以登入流程中部分React Native程式碼展示如何將Flux應用到React Native開發中進行資料管理,(由於程式碼時間較久,存在一些不合理之處請忽略,但不影響Flux資料流的理解):
檢視層View:
登入頁:
...
_login(userName, passWord) {
LoginActions.login({
username: userName,
password: passWord,
...
}, (response) => {
this.props.navigator.resetTo({comp:MainContainer});
}, (error) => {
Alert.alert(
'提示',
'error',
[{ text: '確定' }]
);
});
}
...複製程式碼
主頁:
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()
});
},
...
...
}複製程式碼
登入頁是你的點選互動事件,你通過點選觸發登入呼叫Action,主頁Main會存在登入後返回的使用者資訊,資料來源於你的資料倉儲AppStore,頁面當然還存在頁面監聽者,知道當你的資料改變的時候,知道該如何去更新你的頁面。
行為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),
...
}複製程式碼
觸發一個行為呼叫Action方法進行了網路API的呼叫,進行登入,並返回成功使用者資訊後,通過Dispatcher將資料和訊息分發出去,把接下來的工作交給資料倉儲Store。
資料倉儲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;複製程式碼
在資料倉儲中,你應該定義出倉庫物件AppStore,並對AppDispatcher註冊入各種操作,即當接收到AppDispatcher發來的不同訊息時,運算元據並儲存資料到dataStore中,之後通過AppStore.emit()將更新通知傳送到頁面中,讓頁面進行重新渲染。從而完成整個Flux資料流的閉環。
關於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而引入庫和輔助工具,你也可以使用其他類似工具。
總結
Flux學習和理解需要的是在專案中實際應用進去,同樣只要理解了單向資料流的思想,理解Flux也是很快的,Flux是單向資料流的一種具體架構實現。接下來會再總結關於Redux的理解和使用,同樣也是單向資料流的一種具體實現,基於Flux,但是比Flux更加方便和強大。而當前的很多React開發專案也都基於使用Redux。
雖然搞技術很難,但是做自己喜歡的事情還是很開心的,一起學習,努力奮鬥。