成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

讀redux源碼總結(jié)

worldligang / 482人閱讀

摘要:源碼個人覺得后的代碼就是,后返回的任然是一個函數(shù),可以接受參數(shù),在后面介紹的代碼中有所涉及。源碼中的獲取對象供后面使用,里的對應(yīng)著對象里的,方法可以獲取,也就是對象樹的總數(shù)據(jù)。

redux介紹

redux給我們暴露了這幾個方法

{
  createStore,
  combineReducers,
  bindActionCreators,
  applyMiddleware,
  compose
}

我們來依次介紹下

createStore

創(chuàng)建一個store的寫法:

let store = createStore(reducer, preloadedState, enhancer);

createStore中的三個參數(shù)reducer, preloadedState, enhancer,后面兩個是可選參數(shù),
當我們只傳兩個參數(shù),并且第二個參數(shù)是函數(shù)時,例如:

let store = createStore(reducer, enhancer);

通過閱讀源碼這段

if (typeof preloadedState === "function" && typeof enhancer === "undefined") {
    enhancer = preloadedState
    preloadedState = undefined
  }

我們知道,上面的createStore會被改寫成這樣:

createStore(educer, undefined, enhancer)

再通過閱讀源碼這段:

if (typeof enhancer !== "undefined") {
    if (typeof enhancer !== "function") {
      throw new Error("Expected the enhancer to be a function.")
    }

    return enhancer(createStore)(reducer, preloadedState)
  }

會發(fā)現(xiàn)原來的調(diào)用方式再次發(fā)生了改變,變成了以下這種方式

enhancer(createStore)(reducer, undefined)

所以實例化一個createStore方法,以下兩種是等價的:

第一種
const store = createStore(reducers, applyMiddleware(routeMiddleware, sagaMiddleware, postRedirectMiddleware, pageSizeMiddleware));


第二種
const store = applyMiddleware(routeMiddleware, sagaMiddleware, postRedirectMiddleware, pageSizeMiddleware)(createStore)(reducers);

最后,返回的store對象提供了以下幾個方法給我們使用

dispatch,
subscribe,
getState,
replaceReducer,

getState用來獲取currentState,也就是總state值

subscribe注冊多個監(jiān)聽函數(shù),這些函數(shù)在開發(fā)者調(diào)用dispatch時會依次執(zhí)行

dispatch的入?yún)⑹且粋€對象action,直接會執(zhí)行reducer(action)方法,并且批量執(zhí)行subscribe監(jiān)聽的內(nèi)容,dispatch執(zhí)行結(jié)束后會返回一個action

replaceReducer替換當前的reducer,這個方法在異步的單應(yīng)用中可以使用利用起來,例如,我們不想一次性將所有的reducer交給createStore初始化,而是當異步獲取某個頁面時,再將這個頁面的reducer加上之前的舊reducer,通過replaceReducer方法來替換成最新的。這樣做的好處是,devtools里的redux工具不會展示那么多的信息,只會展示訪問過頁面的信息,更有利于我們的開發(fā),當然了由于reducer的減少,store的體積也會變小,頁面執(zhí)行速度更快。

combineReducers

源碼

export default function combineReducers(reducers) {
  const reducerKeys = Object.keys(reducers)
  const finalReducers = {}
  for (let i = 0; i < reducerKeys.length; i++) {
    const key = reducerKeys[i]

    if (process.env.NODE_ENV !== "production") {
      if (typeof reducers[key] === "undefined") {
        warning(`No reducer provided for key "${key}"`)
      }
    }

    if (typeof reducers[key] === "function") {
      finalReducers[key] = reducers[key]
    }
  }
  const finalReducerKeys = Object.keys(finalReducers)

  let unexpectedKeyCache
  if (process.env.NODE_ENV !== "production") {
    unexpectedKeyCache = {}
  }

  let shapeAssertionError
  try {
    assertReducerShape(finalReducers)
  } catch (e) {
    shapeAssertionError = e
  }

  return function combination(state = {}, action) {
    if (shapeAssertionError) {
      throw shapeAssertionError
    }

    if (process.env.NODE_ENV !== "production") {
      const warningMessage = getUnexpectedStateShapeWarningMessage(
        state,
        finalReducers,
        action,
        unexpectedKeyCache
      )
      if (warningMessage) {
        warning(warningMessage)
      }
    }

    let hasChanged = false
    const nextState = {}
    for (let i = 0; i < finalReducerKeys.length; i++) {
      const key = finalReducerKeys[i]
      const reducer = finalReducers[key]
      const previousStateForKey = state[key]
      const nextStateForKey = reducer(previousStateForKey, action)
      if (typeof nextStateForKey === "undefined") {
        const errorMessage = getUndefinedStateErrorMessage(key, action)
        throw new Error(errorMessage)
      }
      nextState[key] = nextStateForKey
      hasChanged = hasChanged || nextStateForKey !== previousStateForKey
    }
    return hasChanged ? nextState : state
  }
}

通常我們會這樣使用

combineReducers({
    a:reducer1,
    b:reducer2
})

reducer1是一個函數(shù),而combineReducers返回的任然是一個函數(shù),只不過將每個reducer都遍歷了一遍,最后返回的數(shù)據(jù)結(jié)構(gòu)為

{
    a:state1,
    b:state2
}

而如果我們把a跟b替換成了一個唯一的路徑path,這個path跟項目中每個頁面的文件夾對應(yīng)起來,例如:

combineReducers({
    "component/page1/info/":reducer1,
    "component/page2/user/":reducer2
})

而在取state數(shù)據(jù)的時候這樣來取
state["component/page1/info/"]是不是就可以通過文件夾路徑實現(xiàn)模塊化了,當然了我們離模塊化還差一小步,就是不用人工來寫路徑path,而是交給構(gòu)建工具(webpack的loader)來遍歷完成。

compose

源碼

export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

個人覺得compose(a,b,c)(d)后的代碼就是a(b(c(d))),compose后返回的任然是一個函數(shù),可以接受參數(shù),compose在后面介紹的代碼中有所涉及。

applyMiddleware

源碼

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.`
      )
    }
    let chain = []

    const middlewareAPI = {
      getState: store.getState,
      dispatch: (...args) => dispatch(...args)
    }
    chain = middlewares.map(middleware => middleware(middlewareAPI))
    dispatch = compose(...chain)(store.dispatch)

    return {
      ...store,
      dispatch
    }
  }
}

創(chuàng)建一個store的方法:

let store = applyMiddleware(middleware1,middleware2,middleware3)(createStore)(reducers)

中間件middleware1的代碼

function middleware1({ getState }) {
  return (next) => (action) => {
    console.log("will dispatch", action)
    let returnValue = next(action)
    console.log("state after dispatch", getState())
    return returnValue
  }
}

applyMiddleware傳入的參數(shù)為多個中間件,中間件的作用是在執(zhí)行reducers中的switch之前,先執(zhí)行中間件中的代碼。

對應(yīng)源碼中的參數(shù)來講的話,
實例參數(shù)middleware1、middleware2就相當于源碼入?yún)?..middlewares,
實例參數(shù)createStore對應(yīng)著源碼入?yún)reateStore,
實例參數(shù)reducers對應(yīng)著源碼入?yún)?..args。

源碼中的

const store = createStore(...args)

獲取store對象供后面使用,middlewareAPI里的getState對應(yīng)著store對象里的getState,getState()方法可以獲取currentState,也就是redux對象樹的總數(shù)據(jù)。

chain = middlewares.map(middleware => middleware(middlewareAPI))

middlewareAPI提供了getState這個方法,供中間件獲取currenState,這時候chain獲取的數(shù)組是一個返回值為函數(shù)的函數(shù)。

下面這行代碼比較精彩

dispatch = compose(...chain)(store.dispatch)

首先將最原始的store.dispatch方法作為入?yún)ⅲ?/p>

dispatch(action)

就相當于
compose(...chain)(store.dispatch)(action),

同時也相當于
middleware1(middleware2(middleware3((store.dispatch))))(action),

當然這里的middleware1是已經(jīng)只剩下閉包內(nèi)的兩層函數(shù)不是原來的三層函數(shù)體。

最先執(zhí)行的是middleware1,
返回了next(action),

也就相當于
middleware2(middleware3((store.dispatch)))(action),

執(zhí)行完后返回next(action)
就相當于middleware3((store.dispatch))(action),

執(zhí)行完后返回next(action)
就相當于store.dispatch(action)

整個過程我們已經(jīng)弄清楚了,applyMiddleware中間件的執(zhí)行過程就是不斷的next(action),
而只有最后的next才是執(zhí)行dispatch,之前的next只代表的傳遞其他中間件,dispatch方法只在最后一個中間件里執(zhí)行了一次。

個人覺得這個地方結(jié)合了compose之后寫的比較精彩,而且設(shè)計的非常巧妙。

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

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/51699.html

相關(guān)文章

  • redux源碼總結(jié)

    摘要:源碼個人覺得后的代碼就是,后返回的任然是一個函數(shù),可以接受參數(shù),在后面介紹的代碼中有所涉及。源碼中的獲取對象供后面使用,里的對應(yīng)著對象里的,方法可以獲取,也就是對象樹的總數(shù)據(jù)。 redux介紹 redux給我們暴露了這幾個方法 { createStore, combineReducers, bindActionCreators, applyMiddleware, c...

    高璐 評論0 收藏0
  • 深入redux技術(shù)棧

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

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

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

    VPointer 評論0 收藏0
  • [源碼]高性能和可擴展的React-Redux

    摘要:到主菜了,先看它的一看,我們應(yīng)該有個猜測,這貨是個高階函數(shù)??赡苡悬c繞,但就是這么一個個高階函數(shù)組成的,后面會詳細說。定義了一個處理函數(shù)和高階函數(shù)執(zhí)行次的方法,這個方法比上面的復(fù)雜在于它需要檢測參數(shù)是否訂閱了。 注意:文章很長,只想了解邏輯而不深入的,可以直接跳到總結(jié)部分。 初識 首先,從它暴露對外的API開始 ReactReduxContext /* 提供了 React.creat...

    shuibo 評論0 收藏0

發(fā)表評論

0條評論

worldligang

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<