Redux技術架構簡介(二)-- 異步實現

說明:對Redux不瞭解的同窗可先看看這篇文章Redux技術架構簡介(一)html

前言

這裏說的Redux異步實現,是專指Redux中的異步Action實現,而不是指應用的異步實現,由於Redux自己只支持同步action,即發送action,state當即更新;那若是我在發送一個action後,須要state過一段時間再更新呢?按正常的思路redux是沒法處理這種狀況的,下面就來看看異步Action是如何實現的吧!react

須要提的一點是,其實徹底能夠將異步邏輯寫在View中,而後在回調函數中發送action。可是若是你要配合react一塊兒使用,這樣作就違背了react-redux的設計思想,即UI與邏輯的分離(具體的實現能夠在下一篇文章中看到),並且當存在多個異步請求時也很難將異步邏輯抽象出來,因此異步邏輯應該由Redux架構實現,這樣也就必須實現發送異步action了

1. 中間件(Middleware)

爲了解決上面提到的問題,咱們須要引入中間件的概念。npm

(1)時機

中間件執行的時機是在action發起以後,reducer執行以前。json


即在dispatch一個action以後,通過一系列的中間件處理過程,再進行reducer。redux

(2)原理

本質上,中間件就是對dispatch函數的改造。當執行dispatch(action)時,會先調用中間件,進行一些內部邏輯處理,如:添加日誌等,以後再執行dispatch。若是要支持中間件的鏈式調用,必須再返回一個dispatch。
下面是中間件的簡單實現:segmentfault

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
  }
}

(3) 在Redux中應用中間件

可使用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

2. Redux異步實現

(1) Action設計

須要增長三種action異步

  • 通知異步請求發起的action
  • 異步請求成功的action
  • 異步請求失敗的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分別在請求開始前,請求成功後,請求失敗後發送。
## (2) State設計
爲了配合異步Action,能夠在state樹中增長2個屬性:

  • isFetching:表示是否正在處理異步請求。
  • isValidate:表示數據的有效性,他的做用是在異步請求發送失敗後,告訴View當前state的數據是過期的數據。

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;
    }
}

(3) redux-thunk中間件

當設計好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整合技術

參考

Redux 中文文檔
Redux 入門教程-阮一峯

相關文章
相關標籤/搜索