摘要:使用中間件后的也是通過中間件包裝后的。在的位置則進行觸發監聽器,監聽器設置則在中增加。現在來解釋,和對應關系我當時回答的是對應的函數名稱,如果一致的話就會執行。呵呵,那個涂鴉大工程師有問題了如何綁定的呢,怎么確定是而不是。
redux 閑談
起因: 在與涂鴉智能一個web工程師交流過程中,他詢問我dispatch一個action,是如何和reducer 綁定的,dispatch(actionA)只會觸發reducerA卻不會去觸發reducerB.redux 數據流程Github https://github.com/reduxjs/redux
redux 遵循嚴格的單向數據流,以React為例如下圖:
(網圖,侵刪)
通過用戶在ViewUI 進行一個dispatch(action);
Store內部自動通過如下形式Reducer(prevState, action)調用
Reducer返回新的State(newState), state變化后調用Store上的監聽器(store.subscribe(listener))
在listener內部可以通過 store.getState() 方式得到最新的state進行數據操作
初始化redux 的 Store 初始化通過 createStore 方法來進行初始化
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 }) 返回一個reducers
prevState 則為reducer 中state 的初始化默認值,這里默認值為整個狀態樹的默認值
middleware 則為redux 中間件, 增強redux 功能
該部分初始化流程階段,在下面applyMiddleware 會再次調用combineReducers 合并 reducer
在上面說到我們可能存在多個reducer,也可能分模塊來處理不同的狀態問題,這里就需要合并不同模塊的reducer,實現代碼:
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 } }
傳入一個reducers = { authReducer, userReducer }, 很明顯對reducers 進行了對象遍歷,在①這個位置進行了單個reducer函數的拷貝,在②這個位置redux 內部自己創建了一個reducer函數為combination, 在是③這個位置,進行了開發者定義的reducer定義,也就是說dispatch(action) -> combination(state, action) -> customReducer(state, action), 在循環內部每次獲取對應的module 的state值作為 previousStateForKey, 傳入用戶的reducer中,所以用戶dispatch的 action中type是和reducer對應的位置在于用戶自己的判斷
compose 和 applyMiddleware composecompose 函數非常簡短,代碼如下:
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))) }
傳入一個不定量函數作為參數,主要作為函數從一個數組形式例如[login, fetchToken, fetchUser]這樣的函數傳入,得到則是fetchUser(fetchToken(login(...args))) 這樣的形式, 將函數組合起來,并從右到左,而且最右側函數可以接受多個參數
示例僅僅為了說明,不在實際業務中出現applyMiddleware
根據函數字面意思該函數為應用redux 中間件,核心代碼如下:
export default function applyMiddleware(...middlewares) { return createStore => (...args) => { // 這里createStore 通過初始化時候傳入 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后,在 ① 的位置就行了第一個次的中間件調用傳入middlewareAPI,分別為getState 和 dispatch 兩個方法這里對應 example-① 中的 store,在 ② 的位置進行了上文說的compose調用,把所有的中間件進行了組合,從右到左的調用,此刻傳入dispatch 方法,這里方法對應 example-① 中的 next,在上文中說到 compose 對 函數進行了組合,我們這里將store.dispatch 傳入當成參數,返回一個新的函數等價于我們在ViewUI 中dispatch的時候其實使用的 compose(...chain)(store.dispatch)(action) 這樣的方式,所以在 example-① 中action 是開發者的action。使用中間件后的store.dispatch也是通過中間件包裝后的dispatch。在最后 applyMiddleware 把dispatch 返回。
這里有點晦澀難懂在于compose(...chain)(store.dispatch)(action), 這里可以這樣理解,每次dispatch的時候,中間件都是會執行一次,傳入順序是[logger, crashReport], 執行順序為 crashReport -> logger, 自右向左執行。在每個中間件執行過程中都需要返回next(action) 將當前action 繼續傳遞下去dispatch(action)其他參考: redux applyMiddleware 解析
下面說到dispatch,這是我們經常用的,如下代碼:
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 執行reducer 判斷
isDispatching really needed?
這里這個參數解決情況如下:
var store = createStore((state={}, action) => { if (something) { store.dispatch({type: "ANOTHER_ACTION"}) } return state })
繼續下面來說在 ① 的位置執行 currentReducer, 這里reducer 為我們通過 createStore 傳入combineReducers, 把對應的currentState 和 action傳入, currentState 也是在初始階段傳入的 preloadState。在 ② 的位置則進行觸發監聽器, 監聽器設置則在 store.subscribe 中增加。
現在來解釋,action 和 reducer 對應關系我當時回答的是: action.type 對應 reducer 的函數名稱,如果一致的話就會執行。呵呵,那個涂鴉大工程師有問題了如何綁定的呢,怎么確定是reducerA 而不是B。呵呵呵呵呵。NB
后續還問我 redux-saga、redux-thunk 異步處理方案,我提了一下redux-thunk,后續繼續更新。
PS:真應該提升整個溝通流程質量
1.參考地址: https://redux.js.org
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/103748.html
摘要:而的主線程中不允許操作網絡,更是將程序員們推向了異步的深淵。異步深淵產生的主要原因是回調,這在里尤其嚴重。為了逃離回調的深淵,大家開始想各種辦法來把回調扁平化。目前已經在等環境中得到支持,使用的不僅能大大簡化代碼,還能降低邏輯思路的復雜度。 哦,代碼……就把它們當成插圖吧 隨著 CPU 從單核變多核,軟件從注重功能到注重體驗,Web 從頁面跳轉方式到 Web2.0 的無刷新加載(AJA...
摘要:閑談系列不涉及具體的講解,只會勾勾畫畫一些自己認為比較重要的特性。我們一般認為用兩個字節位表示,并且完全囊括了字符集。將其轉換成進制就是只是表示它們是碼。三的讀取和寫入相關重要的只有能夠讀寫,才能夠顯示其存在的價值。 原文地址:http://www.cnblogs.com/DeanCh... 在剛接觸Nodejs的時候,有些概念總讓學前端的我感到困惑(雖然大學的時候也是在搞后端,世界上...
摘要:已經得到了廣大開發者的一致認可。移動市場已經飽和年蘋果發布第一個,同年年末安卓發布。從今年手機的出貨量和身邊的觀察很容易得到這樣的結論移動開發這塊蛋糕的高速增長已經結束了。 showImg(https://segmentfault.com/img/bVEUH9?w=1240&h=518); 移動開發市場潮流涌動,好多人都會問iOS開發的前景這樣的問題,今天我就瞎扯一下我眼中的未來,純主...
閱讀 1759·2021-11-11 16:55
閱讀 2545·2021-08-27 13:11
閱讀 3622·2019-08-30 15:53
閱讀 2301·2019-08-30 15:44
閱讀 1378·2019-08-30 11:20
閱讀 1036·2019-08-30 10:55
閱讀 943·2019-08-29 18:40
閱讀 3029·2019-08-29 16:13