redux中間件

一烘跺、中間件的概念

redux是有流程的,那么镶蹋,我們該把這個異步操作放在哪個環(huán)節(jié)比較合適呢?

  • Reducer?純函數(shù)只承擔計算State功能赏半,不適合其它功能贺归。
  • View?與State一一對應,可以看做是State的視覺層断箫,也不適合承擔其它功能拂酣。
  • Action?它是一個對象仲义,即存儲動作的載體婶熬,只能被操作。

其實埃撵,也只有dispatch能勝任此重任了赵颅。那么怎么在dispatch中添加其它操作呢?

let next = store.dispatch;
store.dispatch = function(action){
   console.log('老狀態(tài) ',store.getState());
   next(action);
   console.log('新狀態(tài) ',store.getState());
}
復制代碼

示例中可以看出暂刘,我們對store.dispatch重新進行了定義饺谬,在發(fā)送action的前后,做了打印鸳惯。

這是中間件的大致雛形商蕴,真實的中間件要比這么復雜多了

二、中間件的用法

我們在這里先看看中間件是怎么使用芝发,下面我們一步步剖析每個細節(jié)绪商。

import {applyMiddleware,createStore} from 'redux';
import reduxLogger form 'redux-logger';

const store = createStore(reducer,inital_state,applyMiddleware(thunk, promise,reduxLogger));

復制代碼

代碼中有兩點需要注意:

  • 1、createStore方法可以整個應用的初始狀態(tài)作為參數(shù) 內(nèi)部是這么處理的
let state = inital_state;
復制代碼
  • 2辅鲸、中間件的參數(shù)次序有講究格郁。下面我會把這個問題講明白。

三、applyMiddleware

Middleware可以讓你包裝storedispatch方法來達到你想要的目的例书。同時锣尉,middleWare還擁有“可組合”這一關鍵特性。多個middleWare可以被組合到一起使用决采,形成middleWare鏈自沧,依次執(zhí)行。其中每個middleware不需要關心鏈前后的的middleWare的任何信息树瞭。

function applyMiddleware(...middlewares){
    return function(createStore){
        return function(reducer){
            //引入store
            let store = createStore(reducer);
            let dispatch = store.dispatch;
            let middlewareAPI = {
                getState:store.getState,
                // 對dispatch進行包裝
                dispatch:action=>dispatch(action)
            }
            //每個中間件都是這種模型  ({ getState, dispatch }) => next => action
            chain = middlewares.map(middleware=>middleware(middleAPI));
            dispatch = compose(...chain)(store.dispatch);
            // dispatch被改裝后拇厢,返回store
            return{...store,dispatch};
        }
    }
}
復制代碼

上面代碼中,所有中間件都被放進了一個數(shù)組chain,然后嵌套執(zhí)行晒喷,最后執(zhí)行store.dispatch孝偎。中間件內(nèi)部middlewaAPI可以拿到getStatedispatch這兩個方法。

...middleware:遵循Redux middleware API的函數(shù)凉敲。每個middleware接受StoredispatchgetState函數(shù)作為命名參數(shù)衣盾,并返回一個函數(shù)。該函數(shù)會被傳入成為next的下一個middleWare 的dispatch方法爷抓,并返回一個接收action的新函數(shù)势决,這個函數(shù)可以直接調(diào)用next(action),或者在其他需要的時刻調(diào)用废赞,甚至根本不去調(diào)用它徽龟。

所以,接下來唉地,我們就能看到middleware的函數(shù)簽名是({ getState, dispatch }) => next => action

其實据悔,它的本質(zhì)就是包裝sotre中的dispatch

上面代碼中耘沼,還用到了compose方法极颓,我們來看看compose是怎么是實現(xiàn)的?

compose

先看下面一個栗子:

function add1(str){
   return str+1;
}
function add2(str){
    return str+2;
 }
 function add3(str){
    return str+3;
 }
 let result = add3(add2(add1('好吃')));// 好吃123;

復制代碼

這中寫法調(diào)用起來群嗤,一層套一層菠隆,是不是看著很不爽,我們簡化一下:

function compose(...fns){
    if(fns.length==1)
     return fns[0];
   return function(...args){
    let last = fns.pop();
    return fns.reduceRight((prev,next)=>{
         return  next(prev);  
    },last(...args));
   }
 }
 let add = compose(add3,add2,add1);//
 let result = add('好吃');// 好吃123
 // 上面的代碼其實就是redux3.6.0版本中compose的實現(xiàn)方式
復制代碼

看看這個代碼是不是用起來狂秘,很干練一些骇径。其實還可以簡化

 function compose(...fns){
  if(fns.length==1)
     return fns[0];
   return fns.reduce((a,b)=>(...args)=>a(b(...args)));//add3(add2(add1('好吃')))
 }
 let add = compose(add3,add2,add1);//
 let result = add('好吃');// 好吃123
 // 這是redux3.6.0版本之后的compose實現(xiàn)方式,一直沿用至今者春。
復制代碼

至于為什么applyMiddleWare的參數(shù)有順序破衔,這里給出了答案。

四钱烟、Applymiddleware的三個常用參數(shù)

4.1晰筛、日志記錄

使用 Redux 的一個益處就是它讓 state 的變化過程變的可預知和透明嫡丙。每當一個 action 發(fā)起完成后,新的 state 就會被計算并保存下來读第。State 不能被自身修改曙博,只能由特定的 action 引起變化。

試想一下怜瞒,當我們的應用中每一個 action 被發(fā)起以及每次新的 state 被計算完成時都將它們記錄下來父泳,豈不是很好?當程序出現(xiàn)問題時吴汪,我們可以通過查閱日志找出是哪個 action 導致了 state 不正確尘吗。

圖片的效果是不是很期待啊=阶!黔宛!

我們先來手動實現(xiàn)一版近刘。

// 記錄所有被發(fā)起的action和新的state
let next = store.dispatch;
store.dispatch = function(action){
   console.log('老狀態(tài) ',store.getState());
   next(action);
   console.log('新狀態(tài) ',store.getState());
}
復制代碼

還是上面的示例,我們來做個修改

let logger = function({ getState, dispatch }){
   return function(next){// 這里的next可以理解為store.dispath,本質(zhì)上就是調(diào)用 middleware 鏈中下一個 middleware 的 dispatch臀晃。
      return function(action){
        console.log('老狀態(tài)1 ',getState());
        next(action);//派發(fā)動作
        console.log('新狀態(tài)1 ',getState());
    }
    }
}
// 高逼格寫法
let logger = ({ getState, dispatch }) => next => action => {
  console.log('老狀態(tài)1 ',getState());
  next(action)
  console.log('新狀態(tài)1 ',getState());
}
復制代碼

4.2觉渴、redux-thunk 中間件

redux-thunkredux官方文檔中用到的異步組件,實質(zhì)就是一個redux中間件徽惋,一個封裝表達式的函數(shù)案淋,封裝的目的就是延遲執(zhí)行表達式。

redux-thunk是一個通用的解決方案险绘,其核心思想是讓action可以變成一個thunk踢京,這樣的話,同步情況:dispatch(action),異步情況:dispatch(thunk)宦棺。

下面是redux-thunk的實現(xiàn):

let thunk = ({dispatch,getState})=>next=>action=>{
    if(typeof action == 'function'){
        action(dispatch,getState);
    }else{
        next(action);//這里可以理解為dispatch(action),本質(zhì)上就是調(diào)用 middleware 鏈中下一個 middleware 的 dispatch瓣距。
    }
}
復制代碼

使用redux-thunk

const store = createStore(  
  reducer,
  applyMiddleware(thunk)
);
復制代碼

然后我們實現(xiàn)一個thunkActionCreator

    //過一秒加1
    export function thunkActionCreator(payload){
        return function(dispatch,getState){
            setTimeout(function(){
                dispatch({type:types.INCREMENT,payload:payload});
            },1000);
        }
    },
復制代碼

最后,在組件中dispatch thunk

this.dispatch(thunkActionCreator(payload));
復制代碼

4.3代咸、redux-promise

redux-promise也是延遲執(zhí)行的表達式蹈丸,它是解決異步的另外一種方案。

redux-thunk和核心思想是把action變成thunk呐芥,而redux-promise的核心思想是讓action返回一個promise對象逻杖。

這個中間件使得store.dispatch方法可以接收Promise對象作為參數(shù)。這時 思瘟,action 有兩種寫法:

寫法一荸百、返回值是一個Promise對象。

function promiseIncrement(payload){
 //  return {type:types.INCREMENT,payload:payload}  以前是這種寫法
    return new Promise(function(resolve,reject){
      setTimeout(function(){
        resolve({type:types.INCREMENT,payload:payload});
      },1000);
    });
 },
復制代碼

寫法二潮太,action 對象的payload屬性是一個Promise對象管搪,這需要從

function payloadIncrement(){
    return {
        type:types.INCREMENT,
        payload: new Promise(function(resolve,reject){
            setTimeout(function(){
                if(Math.random()>.5){
                    resolve(100);
                }else{
                    reject(-100);
                }
            },1000)
        })
    }
}
復制代碼

下面我們來看看 redux-promise是怎么實現(xiàn)的虾攻,就會明白它內(nèi)部是怎么操作的.

let promise = ({dispatch,getState})=>next=>action=>{
    if(action.then && typeof action.then == 'function'){
        action.then(dispatch);
        // 這里的dispatch就是一個函數(shù),dispatch(action){state:reducer(state,action)};
    }else if(action.payload&& action.payload.then&& typeof action.payload.then == 'function'){
        action.payload.then(payload=>dispatch({...action,payload}),payload=>dispatch({...action,payload}));
    }else{
        next(action);
    }
}
復制代碼

上面的代碼可以看出更鲁,如果Action本身就是一個Promise霎箍,它resolve以后的值應該是一個Action對象,會被dispatch方法送出action.then(dispatch)澡为;如果Action對象的 payload屬性是一個Promise對象漂坏,那么無論resolvereject,dispatch 方法都會發(fā)出Action

需要dubbo視頻教程的朋友媒至。加QQ群:957734884領取資料顶别。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市拒啰,隨后出現(xiàn)的幾起案子驯绎,更是在濱河造成了極大的恐慌,老刑警劉巖谋旦,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件剩失,死亡現(xiàn)場離奇詭異,居然都是意外死亡册着,警方通過查閱死者的電腦和手機拴孤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來甲捏,“玉大人演熟,你說我怎么就攤上這事∷径伲” “怎么了芒粹?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長大溜。 經(jīng)常有香客問我是辕,道長,這世上最難降的妖魔是什么猎提? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任获三,我火速辦了婚禮,結(jié)果婚禮上锨苏,老公的妹妹穿的比我還像新娘疙教。我一直安慰自己,他們只是感情好伞租,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布贞谓。 她就那樣靜靜地躺著,像睡著了一般葵诈。 火紅的嫁衣襯著肌膚如雪裸弦。 梳的紋絲不亂的頭發(fā)上祟同,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天,我揣著相機與錄音理疙,去河邊找鬼晕城。 笑死,一個胖子當著我的面吹牛窖贤,可吹牛的內(nèi)容都是我干的砖顷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼赃梧,長吁一口氣:“原來是場噩夢啊……” “哼滤蝠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起授嘀,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤物咳,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后蹄皱,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體所森,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年夯接,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片纷妆。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡盔几,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出掩幢,到底是詐尸還是另有隱情逊拍,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布际邻,位于F島的核電站芯丧,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏世曾。R本人自食惡果不足惜缨恒,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望轮听。 院中可真熱鬧骗露,春花似錦、人聲如沸血巍。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽述寡。三九已至柿隙,卻和暖如春叶洞,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背禀崖。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工衩辟, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人帆焕。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓惭婿,卻偏偏與公主長得像,于是被迫代替她去往敵國和親叶雹。 傳聞我的和親對象是個殘疾皇子财饥,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容