說明:對Redux不瞭解的同窗可先看看這篇文章Redux技術架構簡介(一)html
這裏說的Redux異步實現,是專指Redux中的異步Action實現,而不是指應用的異步實現,由於Redux自己只支持同步action,即發送action,state當即更新;那若是我在發送一個action後,須要state過一段時間再更新呢?按正常的思路redux是沒法處理這種狀況的,下面就來看看異步Action是如何實現的吧!react
須要提的一點是,其實徹底能夠將異步邏輯寫在View中,而後在回調函數中發送action。可是若是你要配合react一塊兒使用,這樣作就違背了react-redux的設計思想,即UI與邏輯的分離(具體的實現能夠在下一篇文章中看到),並且當存在多個異步請求時也很難將異步邏輯抽象出來,因此異步邏輯應該由Redux架構實現,這樣也就必須實現發送異步action了npm
爲了解決上面提到的問題,咱們須要引入中間件的概念。json
中間件執行的時機是在action發起以後,reducer執行以前。redux
本質上,中間件就是對dispatch函數的改造。當執行dispatch(action)時,會先調用中間件,進行一些內部邏輯處理,如:添加日誌等,以後再執行dispatch。若是要支持中間件的鏈式調用,必須再返回一個dispatch。
下面是中間件的簡單實現:bash
function logger(store) {
// 這裏的 next 必須指向前一個 middleware 返回的函數:
const next = store.dispatch
return function dispatchAndLog(action) {
console.log('dispatching', action)
let result = next(action)
console.log('next state', store.getState())
return result
}
}
複製代碼
可使用Redux的API—applyMiddleware直接使用中間件,代碼以下:架構
import {applyMiddleware,createStore} from 'redux';
import {createLogger} from 'redux-logger';//log中間件
import thunk from 'redux-thunk';//將dispatch改形成能夠接受函數做爲參數的中間件
import indexPhotomainReducer from '../reducer/indexPhotomainReducer';
const logger = createLogger();
const store = createStore(
indexPhotomainReducer,
applyMiddleware(thunk, logger)
);
複製代碼
因而可知,能夠把applyMiddleware做爲createStore的第二個參數傳入,你所使用的中間件須要下載單獨npm包,而後按順序傳入applyMiddleware函數中(注:中間件有順序要求,須要看下每一箇中間件的使用文檔,logger通常要放在最後)。app
須要增長三種action異步
示例代碼以下:ide
export const requestPostsAction = () => {
return {
type: REQUEST_POSTS
};
}
export const receivePostsSuccessAction = (data) => {
return {
type: RECEIVE_POSTS_SUCCESS,
data
};
}
export const receivePostsFailureAction = (error) => {
return {
type: RECEIVE_POSTS_FAILURE,
error
};
}
複製代碼
返回參數徹底能夠自定義。這3種action分別在請求開始前,請求成功後,請求失敗後發送。
爲了配合異步Action,能夠在state樹中增長2個屬性:
State屬性能夠憑本身喜愛隨意設計。設計好後能夠這樣編寫reducer:
let sliderReducer = function (state = initialState, action) {
switch(action.type){
case photomainAction.RECEIVE_POSTS_SUCCESS:
return Object.assign({}, state, {photoData,videoData,isFetching:false,isValidate:true});
case photomainAction.RECEIVE_POSTS_FAILURE:
return Object.assign({}, state, {isFetching:false,isValidate:false});
case photomainAction.REQUEST_POSTS:
return Object.assign({}, state, {isFetching:true,isValidate:false});
default:
return state;
}
}
複製代碼
當設計好action和state後,咱們想要達到的效果是--能夠像同步同樣dispatch一個action,而不用考慮異步邏輯。
爲了達到這種效果,首先面臨的問題是,異步邏輯放在哪裏?這裏只有2個選擇:action中或reducer中(store是不適合處理數據的)。因爲reducer必須是一個純函數,他不適合處理像異步請求這樣存在不肯定的輸出的邏輯。最後只能放在action中處理了。
這時,爲了處理異步請求,action建立函數須要返回一個帶有異步請求邏輯的函數,而不是一個對象了。而dispatch只能接受對象,不能接受函數做爲參數,這樣就面臨又一個問題:如何讓dispatch接受函數?
接下來就是redux-thunk中間件發揮做用的時候了,他可讓dispatch接受一個函數(原理就是上一節講的,他實際上是改寫了dispatch函數),最終異步的action能夠這樣實現:
//定義一個action creator – fetchPosts
export const fetchPosts = () => (dispatch, getState) => {
dispatch(requestPostsAction());
return window.fetch("/photo/initPage").then(response=>{
if(response.ok){
return response.json();
}else{
dispatch(receivePostsFailureAction("error"));
}
}).then(data => {
if(data){
dispatch(receivePostsSuccessAction(data));
}else{
dispatch(receivePostsFailureAction("error"));
}
});
}
複製代碼
這樣就能夠像同步同樣發送action了,即:
dispatch(fetchPosts());
複製代碼
接下來只需靜靜等待view的更新就好了,這樣就實現了整個Redux的異步流程。
本篇到此告一段落,下一篇介紹React與Redux整合技術。