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

資訊專欄INFORMATION COLUMN

redux 閑談

levius / 2475人閱讀

摘要:使用中間件后的也是通過中間件包裝后的。在的位置則進(jìn)行觸發(fā)監(jiān)聽器,監(jiān)聽器設(shè)置則在中增加?,F(xiàn)在來解釋,和對應(yīng)關(guān)系我當(dāng)時(shí)回答的是對應(yīng)的函數(shù)名稱,如果一致的話就會(huì)執(zhí)行。呵呵,那個(gè)涂鴉大工程師有問題了如何綁定的呢,怎么確定是而不是。

redux 閑談
起因: 在與涂鴉智能一個(gè)web工程師交流過程中,他詢問我dispatch一個(gè)action,是如何和reducer 綁定的,dispatch(actionA)只會(huì)觸發(fā)reducerA卻不會(huì)去觸發(fā)reducerB.

Github https://github.com/reduxjs/redux

redux 數(shù)據(jù)流程

redux 遵循嚴(yán)格的單向數(shù)據(jù)流,以React為例如下圖:

(網(wǎng)圖,侵刪)

通過用戶在ViewUI 進(jìn)行一個(gè)dispatch(action);

Store內(nèi)部自動(dòng)通過如下形式Reducer(prevState, action)調(diào)用

Reducer返回新的State(newState), state變化后調(diào)用Store上的監(jiān)聽器(store.subscribe(listener))

在listener內(nèi)部可以通過 store.getState() 方式得到最新的state進(jìn)行數(shù)據(jù)操作

初始化

redux 的 Store 初始化通過 createStore 方法來進(jìn)行初始化

const store = createStore(combineReducers, prevState, compose(applyMiddleware(...middleware)))

combineReducers 合并后的reducer,reducer 形式如下

function authReducer(state, action) {

    switch(action.type) {
        case "login":
            return { ...state, isLogin: true }
        default:
            return {...state}
    }
}

function userReducer(state, action) {
    // ...如上
}

通過使用combineReducers({ authReducer, userReducer }) 返回一個(gè)reducers

prevState 則為reducer 中state 的初始化默認(rèn)值,這里默認(rèn)值為整個(gè)狀態(tài)樹的默認(rèn)值

middleware 則為redux 中間件, 增強(qiáng)redux 功能

該部分初始化流程階段,在下面applyMiddleware 會(huì)再次調(diào)用
combineReducers 合并 reducer

在上面說到我們可能存在多個(gè)reducer,也可能分模塊來處理不同的狀態(tài)問題,這里就需要合并不同模塊的reducer,實(shí)現(xiàn)代碼:

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 (typeof reducers[key] === "function") {
      finalReducers[key] = reducers[key] // ①
    }
  }
  const finalReducerKeys = Object.keys(finalReducers)
  
  // 其他代碼...
  
  return function combination(state = {}, action) { // ②
    // 其他代碼...
    
    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
  }
}

傳入一個(gè)reducers = { authReducer, userReducer }, 很明顯對reducers 進(jìn)行了對象遍歷,在①這個(gè)位置進(jìn)行了單個(gè)reducer函數(shù)的拷貝,在②這個(gè)位置redux 內(nèi)部自己創(chuàng)建了一個(gè)reducer函數(shù)為combination, 在是③這個(gè)位置,進(jìn)行了開發(fā)者定義的reducer定義,也就是說dispatch(action) -> combination(state, action) -> customReducer(state, action), 在循環(huán)內(nèi)部每次獲取對應(yīng)的module 的state值作為 previousStateForKey, 傳入用戶的reducer中,所以用戶dispatch的 action中type是和reducer對應(yīng)的位置在于用戶自己的判斷

compose 和 applyMiddleware compose

compose 函數(shù)非常簡短,代碼如下:

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

傳入一個(gè)不定量函數(shù)作為參數(shù),主要作為函數(shù)從一個(gè)數(shù)組形式例如[login, fetchToken, fetchUser]這樣的函數(shù)傳入,得到則是fetchUser(fetchToken(login(...args))) 這樣的形式, 將函數(shù)組合起來,并從右到左,而且最右側(cè)函數(shù)可以接受多個(gè)參數(shù)

示例僅僅為了說明,不在實(shí)際業(yè)務(wù)中出現(xiàn)
applyMiddleware

根據(jù)函數(shù)字面意思該函數(shù)為應(yīng)用redux 中間件,核心代碼如下:

export default function applyMiddleware(...middlewares) {
  return createStore => (...args) => { // 這里createStore 通過初始化時(shí)候傳入
    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)
    }
    const chain = middlewares.map(middleware => middleware(middlewareAPI)) // ①
    dispatch = compose(...chain)(store.dispatch) // ②

    return {
      ...store,
      dispatch
    }
  }
}

示例logger

const logger = store => next => action => { // example-①
  console.log("dispatching", action)
  let result = next(action)
  console.log("next state", store.getState())
  return result
}

// usage: applyMiddleware(logger)

這里applyMiddleware 接受不定量的redux中間件,我們就來解釋一下example-①這里申明是哪里來的。

applyMiddleware 源碼中,傳入middlewares后,在 ① 的位置就行了第一個(gè)次的中間件調(diào)用傳入middlewareAPI,分別為getStatedispatch 兩個(gè)方法這里對應(yīng) example-① 中的 store,在 ② 的位置進(jìn)行了上文說的compose調(diào)用,把所有的中間件進(jìn)行了組合,從右到左的調(diào)用,此刻傳入dispatch 方法,這里方法對應(yīng) example-① 中的 next,在上文中說到 compose 對 函數(shù)進(jìn)行了組合,我們這里將store.dispatch 傳入當(dāng)成參數(shù),返回一個(gè)新的函數(shù)等價(jià)于我們在ViewUI 中dispatch的時(shí)候其實(shí)使用的 compose(...chain)(store.dispatch)(action) 這樣的方式,所以在 example-① 中action 是開發(fā)者的action。使用中間件后的store.dispatch也是通過中間件包裝后的dispatch。在最后 applyMiddleware 把dispatch 返回。

這里有點(diǎn)晦澀難懂在于compose(...chain)(store.dispatch)(action), 這里可以這樣理解,每次dispatch的時(shí)候,中間件都是會(huì)執(zhí)行一次,傳入順序是[logger, crashReport], 執(zhí)行順序?yàn)?crashReport -> logger, 自右向左執(zhí)行。在每個(gè)中間件執(zhí)行過程中都需要返回next(action) 將當(dāng)前action 繼續(xù)傳遞下去

其他參考: redux applyMiddleware 解析

dispatch(action)

下面說到dispatch,這是我們經(jīng)常用的,如下代碼:

function dispatch(action) {
    // 其他代碼

    try {
      isDispatching = true
      currentState = currentReducer(currentState, action) // ①
    } finally {
      isDispatching = false
    }

    const listeners = (currentListeners = nextListeners)
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i]
      listener() // ②
    }

    return action
  }

這里先說一下 isDispatching 作用, isDispatching 執(zhí)行reducer 判斷

isDispatching really needed?

這里這個(gè)參數(shù)解決情況如下:

var store = createStore((state={}, action) => {
  if (something) {
    store.dispatch({type: "ANOTHER_ACTION"})
  }
  return state
})

繼續(xù)下面來說在 ① 的位置執(zhí)行 currentReducer, 這里reducer 為我們通過 createStore 傳入combineReducers, 把對應(yīng)的currentState 和 action傳入, currentState 也是在初始階段傳入的 preloadState。在 ② 的位置則進(jìn)行觸發(fā)監(jiān)聽器, 監(jiān)聽器設(shè)置則在 store.subscribe 中增加。

現(xiàn)在來解釋,action 和 reducer 對應(yīng)關(guān)系

我當(dāng)時(shí)回答的是: action.type 對應(yīng) reducer 的函數(shù)名稱,如果一致的話就會(huì)執(zhí)行。呵呵,那個(gè)涂鴉大工程師有問題了如何綁定的呢,怎么確定是reducerA 而不是B。呵呵呵呵呵。NB

后續(xù)

還問我 redux-saga、redux-thunk 異步處理方案,我提了一下redux-thunk,后續(xù)繼續(xù)更新。

PS:真應(yīng)該提升整個(gè)溝通流程質(zhì)量

1.參考地址: https://redux.js.org

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

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

相關(guān)文章

  • 閑談異步調(diào)用“扁平”化

    摘要:而的主線程中不允許操作網(wǎng)絡(luò),更是將程序員們推向了異步的深淵。異步深淵產(chǎn)生的主要原因是回調(diào),這在里尤其嚴(yán)重。為了逃離回調(diào)的深淵,大家開始想各種辦法來把回調(diào)扁平化。目前已經(jīng)在等環(huán)境中得到支持,使用的不僅能大大簡化代碼,還能降低邏輯思路的復(fù)雜度。 哦,代碼……就把它們當(dāng)成插圖吧 隨著 CPU 從單核變多核,軟件從注重功能到注重體驗(yàn),Web 從頁面跳轉(zhuǎn)方式到 Web2.0 的無刷新加載(AJA...

    Jaden 評(píng)論0 收藏0
  • Node閑談之Buffer

    摘要:閑談系列不涉及具體的講解,只會(huì)勾勾畫畫一些自己認(rèn)為比較重要的特性。我們一般認(rèn)為用兩個(gè)字節(jié)位表示,并且完全囊括了字符集。將其轉(zhuǎn)換成進(jìn)制就是只是表示它們是碼。三的讀取和寫入相關(guān)重要的只有能夠讀寫,才能夠顯示其存在的價(jià)值。 原文地址:http://www.cnblogs.com/DeanCh... 在剛接觸Nodejs的時(shí)候,有些概念總讓學(xué)前端的我感到困惑(雖然大學(xué)的時(shí)候也是在搞后端,世界上...

    Godtoy 評(píng)論0 收藏0
  • 2016年末閑談iOS開發(fā)的未來

    摘要:已經(jīng)得到了廣大開發(fā)者的一致認(rèn)可。移動(dòng)市場已經(jīng)飽和年蘋果發(fā)布第一個(gè),同年年末安卓發(fā)布。從今年手機(jī)的出貨量和身邊的觀察很容易得到這樣的結(jié)論移動(dòng)開發(fā)這塊蛋糕的高速增長已經(jīng)結(jié)束了。 showImg(https://segmentfault.com/img/bVEUH9?w=1240&h=518); 移動(dòng)開發(fā)市場潮流涌動(dòng),好多人都會(huì)問iOS開發(fā)的前景這樣的問題,今天我就瞎扯一下我眼中的未來,純主...

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

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

0條評(píng)論

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