Redux中介軟體在React和React-Native專案架構中的應用實踐
前言
在MVVM框架模式獨攬天下的今天,React憑藉其獨特的設計思想,深入的設計理念,開闢了一條嶄新的康莊大道,實屬是一個重大的突破,為什麼這麼說呢?因為React論其設計思想,充其量只是MVVM種的V而已,對於大量而且複雜的資料來講,自身處理上顯得有些力不從心,這時候,傳統的Redux和Flux的設計思想起到了決定性的作用,對於Redux和Flux這裡不多贅述,這個觀念在這兩年被炒的異常火熱,網上我們可以搜到很多的資源,最重要的是,單向資料流的觀念越來越被眾多的開發者應用於專案架構之中,一定程度上來講這種設計思想,很大程度上提升了應用的效能,對此我就來談談我再React專案中的應用實踐以及相應的觀點。
react-redux分析
其實,Redux和React兩個框架之間並沒有絕對的聯絡,他們都是獨立的JS框架,一個出於View層,一個用於state管理,兩者之間可以相互使用,但是API融合度並不是很高,使用起來不是特別的方便,於是便有了React-redux, 藉助react-redux這個庫提供一些封裝,一種更科學的程式碼組織方式,讓我們更舒服地在React的程式碼中使用Redux。
react-redux主要提供的常用介面有:
provider: Provider這個模組是作為整個App的容器,在你原有的App Container的基礎上再包上一層,用於傳遞props。
connect:
Store的作用與分析
store翻譯過來講就是儲存,這個模組有redux提供,而不是react-redux, 主要用於儲存應用所有的state。類似於一個大的臨時儲存資料庫。
建立程式碼也很簡單:
....
import { applyMiddleware, createStore, compose } from 'redux';
....
const store = createStore(reducers, undefined, middlewares);
.....
.....
Action的作用分析
action顧名思義就是各種操作,對於redux來講,view的每一種處理都會對應一種操作,每個action的定義也很簡單,主要變數是一個type,定義了當前action是處理什麼的。
view ==> dispatch ===> action
通常,也有開發者會在action中訪問請求資料,比如http資料請求等等。
看下程式碼:
const loginAction = (data) => {
return {type: LOGIN_REQUEST, payload: data}
}
上面這個action可以通過dispatch進行分發處理到對應的reducers.
Reducer的作用
上面講到action會定義各種操作,比如登陸,驗證等等,那麼接下來資料會怎麼處理,進一步更新state呢?
這就要提到reducer的作用了,reducer主要處理各種資料邏輯,篩選,過濾等操作,處理完成後,會返回一個新的state,在更新到view上顯示。
所以reducer的作用,在整個環節還是至關重要的。
我們看一個reducer的程式碼:
import { handleActions } from 'redux-actions';
import * as types from './word-constants';
import { combineReducers } from 'redux';
const getJokesList = handleActions({
[types.SUCCESS_FETCH_DATA]: (state, action) => {
state = action.payload;
console.log(action.payload);
return [...state];
}
}, []);
export default combineReducers({getJokesList});
上面程式碼中,我們暫且不管handleAcions的作用,主要看state的處理,這裡傳遞給state一個新的資料,最後通過拓展運算子…返回。
當然這只是一個例子,真實專案中可能要處理很複雜的資料結構。
applyMiddleware分析
redux在react的專案中,角色主要是資料管理,既然是資料管理,就是多少會有點中介軟體的意思,所以也有很多人說,redux在react專案架構中就是一箇中間件的角色,這個我很贊同,因為redux真的提供了各種豐富的中間,方便我們使用,那麼應用這些中介軟體,就需要applyMiddleware來實現了。
我們來看看:
...
const middlewares = compose(applyMiddleware(sagaMiddleware, thunk, logger), autoRehydrate());
const store = createStore(reducers, undefined, middlewares);
...
上面主要應用了三個中介軟體,thunk, saga, log.
下面我們會依次講解。
常用中介軟體
redux的中間真的很多,但是本人沒有一一嘗試,對於在專案中我比較常用的,這裡和大家分享一下。
react-thunk分析
這個中介軟體在網上會看到很多資料,說的很高大上,最開始我也雲裡霧裡,但是究其根本,用它就一個好處: 方便在action中接收dispatch和getState兩個引數,也就是我們不需要在觸發action時候傳遞這兩個引數,我們就能獲取到。
主要是因為react-thunk會在非同步處理中預設傳過來,以便於我們在action中進一步dispatch其他的操作。
看一下程式碼:
/**
* Created by Richard on 12/20/16.
*/
import { createAction } from 'redux-actions';
import { GET_CONTACTS } from './constants';
import { SAVE_DATA } from './constants';
import fetch from 'isomorphic-fetch';
export const getContacts = createAction(GET_CONTACTS);
export const saveData = createAction(SAVE_DATA);
export const getData = () => (dispatch, getState) => {
fetch('http://offline-news-api.herokuapp.com/stories')
.then(function(response) {
if (response.status >= 400) {
throw new Error("Bad response from server");
}
return response.json();
})
.then(function(stories) {
console.log(stories);
dispatch(getContacts(stories));
});
}
reselect分析
我認為這個reselect其實算不上redux的中介軟體,因為他不來源於redux。但是這個外掛和redux配合使用,在專案中的確帶來很多好處。
reselect主要用於分析處理reducer傳遞過來的state, 並且判斷當前的state和上一個state是否為同一個,同一個即不重新整理頁面,在一定程度上有助於提高效率。
而且在進一步處理state的業務邏輯上, 也提供了一些action,可以方便的處理不同模組下的state關係。
看一下程式碼:
/**
* Created by Richard on 1/11/17.
*/
import { createSelector } from 'reselect';
export const getAllItems = createSelector(
[
state => state.word.getJokesList,
],
(items) => {
return items;
}
);
還有很多語法,需要大家自己摸索一下啦,很好用。
redux-actions分析
redux-actions這個顧名思義就是集中處理所有action的,方便使用,即簡化了程式碼,主要會應用到action和reducer中,在action中建立,在reducer中接收。
我們看一下程式碼:
/**
* Created by Richard on 12/30/16.
*/
import { createAction } from 'redux-actions';
import * as types from './word-constants';
export const successFetchData = createAction(types.SUCCESS_FETCH_DATA);
/**
* Created by Richard on 12/29/16.
*/
import { handleActions } from 'redux-actions';
import * as types from './word-constants';
import { combineReducers } from 'redux';
const getJokesList = handleActions({
[types.SUCCESS_FETCH_DATA]: (state, action) => {
state = action.payload;
console.log(action.payload);
return [...state];
}
}, []);
export default combineReducers({getJokesList});
程式碼中,我們用createAction建立一個action,以便省略了type引數,與此同時,會自動生一個一個payload引數用於傳遞資料到reducer中。
同樣在reducer中我們可以使用handleAction接收對應的action。
redux-saga分析
對於中型專案來講,我們需要處理很多業務邏輯,因為js沒有多執行緒而言(排除webworker). 大多數都是非同步回撥處理,所以複雜的非同步多少讓你的程式碼雜亂,redux-saga主要作用在於處理各種複雜的非同步操作,從而減少程式碼量,簡化action的操作。
看一下程式碼:
/**
* Created by Richard on 1/11/17.
*/
import { call, put, take, select } from 'redux-saga/effects';
import { get, getPicturesUrl } from '../../../utils/api';
import { successFetchPictureData } from './picture-list-actions';
import * as types from './picture-list-constants';
export default function* pictureFlow() {
try {
yield take(types.START_FETH_PICTURE);
const data = yield call(get, getPicturesUrl());
yield put(successFetchPictureData(data));
} catch (e){
}
}
對於saga的更多資訊,歡迎大家閱讀我寫的saga應用一篇文章。
總結
單對Redux而言,每一個框架都是一個故事,都值得我們仔細品味,無論從程式碼簡化上,還是後期維護上,都起著至關重要的作用,弄清楚每個框架的功能和作用,才能更好的在架構中加以設計。