国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

十分鐘理解Redux中間件

i_garfileo / 3062人閱讀

摘要:最后看一下這時(shí)候執(zhí)行返回,如下調(diào)用執(zhí)行循序調(diào)用第層中間件返回即調(diào)用第層中間件返回即調(diào)用根返回即調(diào)用一個(gè)例子讀懂上文提到是個(gè)柯里化函數(shù),可以看成是將所有函數(shù)合并成一個(gè)函數(shù)并返回的函數(shù)。

由于一直用業(yè)界封裝好的如redux-logger、redux-thunk此類的中間件,并沒有深入去了解過redux中間件的實(shí)現(xiàn)方式。正好前些時(shí)間有個(gè)需求需要對(duì)action執(zhí)行時(shí)做一些封裝,于是借此了解了下Redux Middleware的原理。
* 中間件概念

首先簡(jiǎn)單提下什么是中間件,該部分與下文關(guān)系不大,可以跳過。來看眼這個(gè)經(jīng)典的圖。

不難發(fā)現(xiàn):

不使用middleware時(shí),在dispatch(action)時(shí)會(huì)執(zhí)行rootReducer,并根據(jù)actiontype更新返回相應(yīng)的state。

而在使用middleware時(shí),簡(jiǎn)言之,middleware會(huì)將我們當(dāng)前的action做相應(yīng)的處理,隨后再交付rootReducer執(zhí)行。

簡(jiǎn)單實(shí)現(xiàn)原理

比如現(xiàn)有一個(gè)action如下:

function getData() {
  return {
      api: "/cgi/getData",
      type: [GET_DATA, GET_DATA_SUCCESS, GET_DATA_FAIL]
  }
}

我們希望執(zhí)行該action時(shí)可以發(fā)起相應(yīng)請(qǐng)求,并且根據(jù)請(qǐng)求結(jié)果由定義的type匹配到相應(yīng)的reducer,那么可以自定義方法處理該action,因此該方法封裝成中間件之前可能是這樣的:

async function dispatchPre(action, dispatch) {
    const api = action.api;
    const [ fetching_type, success_type,  fail_type] = action.type;
    // 拉取數(shù)據(jù)
    const res = await request(api);
    
    // 拉取時(shí)狀態(tài)
    dispatch({type: fetching_type});
    // 成功時(shí)狀態(tài)
    if (res.success) {
        dispatch({type: success_type, data: res.data});
        console.log("GET_SUCCESS");
    }
    // 失敗時(shí)狀態(tài)
    if (res.fail) {
        dispatch({type: fail_type});
        console.log("GET_FAIL");
    };
}

// 調(diào)用: dispatchPre(action(), dispatch)

那如何封裝成中間件,讓我們?cè)诳梢灾苯釉?b>dispatch(action)時(shí)就做到這樣呢?可能會(huì)首先想到改變dispatch指向

// 儲(chǔ)存原來的dispatch
const dispatch = store.dispatch;
// 改變dispatch指向
store.dispatch = dispatchPre;
// 重命名
const next = dispatch;

截止到這我們已經(jīng)了解了中間件的基本原理了~

源碼分析

了解了基本原理能有助于我們更快地讀懂middleware的源碼。
業(yè)務(wù)中,一般我們會(huì)這樣添加中間件并使用。

createStore(rootReducer, applyMiddleware.apply(null, [...middlewares]))

接下來我們可以重點(diǎn)關(guān)注這兩個(gè)函數(shù)createStore、applyMiddleware

CreateStore
// 摘至createStore
export function createStore(reducer, rootState, enhance) {
    ...
    if (typeof enhancer !== "undefined") {
        if (typeof enhancer !== "function") {
          throw new Error("Expected the enhancer to be a function.")
        }
    /*
        若使用中間件,這里 enhancer 即為 applyMiddleware()
        若有enhance,直接返回一個(gè)增強(qiáng)的createStore方法,可以類比成react的高階函數(shù)
    */
    return enhancer(createStore)(reducer, preloadedState)
  }
  ...
}
ApplyMiddleware

再看看applyMiddleware做了什么,applyMiddleware函數(shù)非常簡(jiǎn)單,就十來行代碼,這里將其完整復(fù)制出來。

export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => {
    const store = createStore(...args)
    let dispatch = () => {
      throw new Error(
        `Dispatching while constructing your middleware is not allowed. ` +
          `Other middleware would not be applied to this dispatch.`
      )
    }

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    // 1、將store對(duì)象的基本方法傳遞給中間件并依次調(diào)用中間件
    const chain = middlewares.map(middleware => middleware(middlewareAPI))
    // 2、改變dispatch指向,并將最初的dispatch傳遞給compose
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}
執(zhí)行步驟

根據(jù)源碼,我們可以將其主要功能按步驟劃分如下:

1、依次執(zhí)行middleware。

middleware執(zhí)行后返回的函數(shù)合并到一個(gè)chain數(shù)組,這里我們有必要看看標(biāo)準(zhǔn)middleware的定義格式,如下

export default store => next => action => {}

// 即
function (store) {
    return function(next) {
        return function (action) {
            return {}
        }
    }
}

那么此時(shí)合并的chain結(jié)構(gòu)如下

[    ...,
    function(next) {
        return function (action) {
            return {}
        }
    }
]

2、改變dispatch指向。

想必你也注意到了compose函數(shù),compose函數(shù)如下:
[...chain].reduce((a, b) => (...args) => a(b(...args)))
實(shí)際就是一個(gè)柯里化函數(shù),即將所有的middleware合并成一個(gè)middleware,并在最后一個(gè)middleware中傳入當(dāng)前的dispatch

*compose可能會(huì)看得有點(diǎn)蒙,不理解柯里化函數(shù)的同學(xué)可以跳到一個(gè)例子讀懂compose先了解下。

// 假設(shè)chain如下:
chain = [
    a: next => action => { console.log("第1層中間件") return next(action) }
    b: next => action => { console.log("第2層中間件") return next(action) }
    c: next => action => { console.log("根dispatch") return next(action) }
]

調(diào)用compose(...chain)(store.dispatch)后返回a(b(c(dispatch)))。
可以發(fā)現(xiàn)已經(jīng)將所有middleware串聯(lián)起來了,并同時(shí)修改了dispatch的指向。
最后看一下這時(shí)候compose執(zhí)行返回,如下

dispatch = a(b(c(dispatch)))

// 調(diào)用dispatch(action)
// 執(zhí)行循序
/*
   1. 調(diào)用 a(b(c(dispatch)))(action) __print__: 第1層中間件
   2. 返回 a: next(action) 即b(c(dispatch))(action)
   3. 調(diào)用 b(c(dispatch))(action) __print__: 第2層中間件
   4. 返回 b: next(action) 即c(dispatch)(action)
   5. 調(diào)用 c(dispatch)(action) __print__: 根dispatch
   6. 返回 c: next(action) 即dispatch(action)
   7. 調(diào)用 dispatch(action)
*/
*一個(gè)例子讀懂compose

上文提到compose是個(gè)柯里化函數(shù),可以看成是將所有函數(shù)合并成一個(gè)函數(shù)并返回的函數(shù)。
例如先定義3個(gè)方法

function A(x){
    return x + "a"
}

function B(y){
    return y + "b"
}

function C(){
    return "c"
}

var d = [...A, b, C].reduce((a, b) => (d) => {console.log(d, a, b); a(b(d))})

d // 打印d

// f (d) { console.log(d, a, b); return a(b(d)) }

d("d") // 調(diào)用d

/*
 * d
 * f(d) { console.log(d, a, b); return a(b(d)) }
 * f C() { return "c" }
*/

/*
 * c
 * f A(x) { return x + "a" }
 * f B(y) { return y + "b" }
*/

不難發(fā)現(xiàn),使用閉包,在調(diào)用d的時(shí)候,將a、b函數(shù)儲(chǔ)存在了內(nèi)存中,調(diào)用時(shí)會(huì)依次將數(shù)組從右至左的函數(shù)返回做為參數(shù)傳遞給下一個(gè)函數(shù)使用

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/102239.html

相關(guān)文章

  • 深入redux技術(shù)棧

    摘要:另外,內(nèi)置的函數(shù)在經(jīng)過一系列校驗(yàn)后,觸發(fā),之后被更改,之后依次調(diào)用監(jiān)聽,完成整個(gè)狀態(tài)樹的更新??偠灾?,遵守這套規(guī)范并不是強(qiáng)制性的,但是項(xiàng)目一旦稍微復(fù)雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進(jìn)階漫談的第二篇,這一篇主要分析redux的思想和應(yīng)用,同樣參考了網(wǎng)絡(luò)上的大量資料,但代碼同樣都是自己嘗試實(shí)踐所得,在這里分享出來,僅供一起學(xué)習(xí)(上一篇地址:個(gè)人博客/s...

    imingyu 評(píng)論0 收藏0
  • 深入redux技術(shù)棧

    摘要:另外,內(nèi)置的函數(shù)在經(jīng)過一系列校驗(yàn)后,觸發(fā),之后被更改,之后依次調(diào)用監(jiān)聽,完成整個(gè)狀態(tài)樹的更新。總而言之,遵守這套規(guī)范并不是強(qiáng)制性的,但是項(xiàng)目一旦稍微復(fù)雜一些,這樣做的好處就可以充分彰顯出來。 這一篇是接上一篇react進(jìn)階漫談的第二篇,這一篇主要分析redux的思想和應(yīng)用,同樣參考了網(wǎng)絡(luò)上的大量資料,但代碼同樣都是自己嘗試實(shí)踐所得,在這里分享出來,僅供一起學(xué)習(xí)(上一篇地址:個(gè)人博客/s...

    VPointer 評(píng)論0 收藏0
  • Redux 進(jìn)階 - react 全家桶學(xué)習(xí)筆記(二)

    摘要:在函數(shù)式編程中,異步操作修改全局變量等與函數(shù)外部環(huán)境發(fā)生的交互叫做副作用通常認(rèn)為這些操作是邪惡骯臟的,并且也是導(dǎo)致的源頭。 注:這篇是17年1月的文章,搬運(yùn)自本人 blog... https://github.com/BuptStEve/... 零、前言 在上一篇中介紹了 Redux 的各項(xiàng)基礎(chǔ) api。接著一步一步地介紹如何與 React 進(jìn)行結(jié)合,并從引入過程中遇到的各個(gè)痛點(diǎn)引出 ...

    Godtoy 評(píng)論0 收藏0
  • redux源碼解讀--applyMiddleware源碼解析

    摘要:的中間件主要是通過模塊實(shí)現(xiàn)的。返回的也是一個(gè)對(duì)象這個(gè)其實(shí)就是,各個(gè)中間件的最底層第三層的哪個(gè)函數(shù)組成的圓環(huán)函數(shù)構(gòu)成的這就是對(duì)源碼的一個(gè)整體解讀,水平有限,歡迎拍磚。后續(xù)的源碼解讀和測(cè)試?yán)涌梢躁P(guān)注源碼解讀倉庫 applyMiddleware源碼解析 中間件機(jī)制在redux中是強(qiáng)大且便捷的,利用redux的中間件我們能夠?qū)崿F(xiàn)日志記錄,異步調(diào)用等多種十分實(shí)用的功能。redux的中間件主要是...

    Atom 評(píng)論0 收藏0
  • 理解redux

    摘要:假如說是士兵的話那么就是將軍,來管理士兵的狀態(tài)。對(duì)于來說,也就是一個(gè)最外層的容器,全部作為該容器組件的類似于,這樣一來發(fā)生變化,就會(huì)重新渲染整個(gè)頁面,從而達(dá)到更新的效果。得益于,每次并不用更新整個(gè)樹。規(guī)定,對(duì)外不暴露任何修改數(shù)據(jù)的接口。 redux 為什么引入redux 以react來說,state可以包含內(nèi)部的狀態(tài)以及業(yè)務(wù)數(shù)據(jù),對(duì)于一個(gè)復(fù)雜的應(yīng)用來說,state非常難以管理,一個(gè)mo...

    piapia 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<