redux深入理解之中介軟體(middleware)
本文程式碼請看本人github,
關於redux運用,請看之前一篇文章http://blog.csdn.net/yuzhongzi81/article/details/51880577
理解reduce
函式 reduce() 方法接收一個函式作為累加器(accumulator),陣列中的每個值(從左到右)開始縮減,最終為一個值。
arr.reduce([callback, initialValue])
關於reduce
的用法,這裡不再做多述,可以去檢視
看如下例子:
let arr = [1, 2, 3, 4, 5];
// 10代表初始值,p代表每一次的累加值,在第一次為10
// 如果不存在初始值,那麼p第一次值為1
// 此時累加的結果為15
let sum = arr.reduce((p, c) => p + c, 10); // 25
// 轉成es5的寫法即為:
var sum = arr.reduce(function(p, c) {
console.log(p);
return p + c;
}, 10);
下面我們再來看一個reduce
的高階擴充套件。現在有這麼一個資料結構,如下:
let school = {
name: 'Hope middle school',
created: '2001',
classes: [
{
name: '三年二班',
teachers: [
{ name: '張二蛋', age: 26, sex: '男', actor: '班主任' },
{ name: '王小妞', age: 23, sex: '女', actor: '英語老師' }
]
},
{
name: '明星班',
teachers: [
{ name: '歐陽娜娜', age: 29, sex: '女', actor: '班主任' },
{ name: '李易峰', age: 28, sex: '男', actor: '體育老師' },
{ name: '楊冪', age: 111, sex: '女', actor: '藝術老師' }
]
}
]
};
比如我想取到這個學校的第一個班級的第一個老師的名字,可能你會這樣寫:
school.classes[0].teachers[0].name
這樣不就行了麼?so easy!是哦,這樣寫"毫無問題",這個毫無問題的前提是你已經知道了這個值確實存在,那麼如果你不知道呢?或許你要這麼寫:
school.classes &&
school.classes[0] &&
school.classes[0].teachers &&
school.classes[0].teachers[0] &&
school.classes[0].teachers[0].name
我去,好大一坨,不過要在深層的物件中取值的場景在工作中真真實實存在呀?怎麼辦?逛知乎逛到一個大神的,如下:
const get = (p, o) => p.reduce((xs, x) => (xs && xs[x] ? xs[x] : null), o);
// call
get('classes', 0, 'teachers', 0, 'name', school); // 張二蛋
是不是很簡單,用reduce
這個方法優雅地解決了這個問題。
compose
函式 講了這麼久的reduce,這不是講redux麼?這就尷尬了,下面我們就來看看為什麼要講這個reduce
函式。去github上找到redux原始碼,會看到一個compose.js檔案,帶上註釋共22行,其中就用到了reduce這個函式,那麼這個函式是用來做啥的?可以看一看:
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)))
}
初步看上去貌似就是函式的巢狀呼叫。我們去搜一下,看哪個地方會用到這個函式,在原始碼中找一下,發現在applyMiddleware.js
中發現了這樣的呼叫:
export default function applyMiddleware(...middlewares) {
return (createStore) => (reducer, preloadedState, enhancer) => {
const store = createStore(reducer, preloadedState, enhancer)
let dispatch = store.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
}
}
}
看到熟悉的東西了麼?applyMiddleware
喲,我們在寫中介軟體必須要用的函式。我們來看一下一個簡單的middleware
是怎樣寫的?比如我要寫一個loggerMiddleware
,那麼就像這樣:
const logger = store => next => action => {
console.log('action', action);
let result = next(action);
console.log('logger after atate', store.getState());
return result;
}
當我們建立了一個store的時候,我們是這樣呼叫的:
let middlewares = [loggerMiddleware, thunkMiddleware, ...others];
let store = applyMiddleware(middlewares)(createStore)(reducer, initialState);
那麼傳給compose的funcs實際上就是包含這樣的函式的一個陣列:
function(next) {
return function(action) {
return next(action);
}
}
當把這樣的一個陣列傳給compose會發生什麼樣的化學反應呢?稍微看一下應該不難看出,最終會返回一個函式,這個函式是透過了層層middleware的加工,最終的形態仍如上面的這個樣子。注意,此時的next(action)
並未執行,當執行了
compose(...chain)(store.dispatch)
之後,返回的樣子是這樣的:
function(action) {
return next(action);
}
各位看官們,看出了一點點什麼東西了麼?好像createStore
中的dispatch呀,沒錯,這其實也是一個dispatch,只是這個dispatch正一觸即發,再等待一個機會。我們有這麼一個數量加1的action,類似這樣的:
export function addCount() {
return {
type : ADD_COUNT
}
}
// 下面我們來觸發一下
dispatch(addCount());
沒錯,此時的dispatch執行啦,最外層的dispatch執行了會發生什麼樣的反應呢?看下面:
return next(action);
// 這個next就是dispatch函式,只不過這個dispatch函式在每次執行的時候,會保留
// 上一個middleware傳遞的dispatch函式的引用,因此會一直的傳遞下去,
// 直到最終的store.dispatch執行
那麼我們去createStore中去看看dispatch函式的定義:
function dispatch(action) {
// ...
try {
isDispatching = true
currentState = currentReducer(currentState, action)
} finally {
isDispatching = false
}
// ...
return action
}
找到這一句
currentState = currentReducer(currentState, action);
當執行了這一步的時候,這一刻,原本傳遞過來的initialState值已經改變了,那麼就會層層執行middleware之後的操作,還記得我們在middleware中這樣寫了麼:
const logger = store => next => action => {
console.log('action', action);
let result = next(action);
console.log('logger after atate', store.getState());
return result;
}
這就是為什麼我們會在next執行之後,會取到store中的state的原因。
非同步的middlewares非同步的action寫法上可能會和立即執行的action不一樣,例如是這樣的:
// 定義的非純函式,提供非同步請求支援
// 需要在sotre中使用thunkMiddleware
export function refresh() {
return dispatch => {
dispatch(refreshStart());
return fetch(`src/mock/fetch-data-mock.json`)
.then(response => response.json())
.then(json => {
setTimeout(() => {
dispatch(refreshSuccess(json && json.data.list));
}, 3000);
});
}
}
為什麼要使用thunkMiddleware呢,我們去找一找thunkMiddleware中到底寫了什麼?
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;
export default thunk;
短短14行程式碼,看這一句:
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
如果action的型別為function的話,那麼就直接執行啦,實際上就是將一個非同步的操作轉化成了兩個立即執行的action,只是需要在非同步前和非同步後分別傳送狀態。為什麼要分解呢?如果不分解會是什麼樣的情況?還記得這一行程式碼嗎?
currentReducer(currentState, action);
這裡的reducer只接受純函式,只接受純函式,只接受純函式,重要的事情說三遍。所以你傳個非純函式是個什麼鬼?那不是直接走switch
的default
了麼?所以得到的state依舊是之前的state,沒有任何改變。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2370/viewspace-2808015/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 深入理解 Redux 中介軟體Redux
- Redux Middleware中介軟體原始碼 分析Redux原始碼
- 理解Redux中介軟體Redux
- Redux的中介軟體Middleware不難,我信了^_^Redux
- 中介軟體(middleware)
- redux中介軟體之redux-thunkRedux
- Sanic middleware – 中介軟體
- 學習 redux 原始碼整體架構,深入理解 redux 及其中介軟體原理Redux原始碼架構
- 筆記:中介軟體 middleware筆記
- middleware 中介軟體詳解
- redux中介軟體Redux
- Redux中介軟體之redux-thunk使用詳解Redux
- 深入淺出redux-middlewareRedux
- .NET Core 自定義中介軟體 Middleware
- redux中介軟體的原始碼的一些理解Redux原始碼
- 深入理解訊息中介軟體技術之RabbitMQ服務MQ
- Redux專題:中介軟體Redux
- React+Redux+中介軟體ReactRedux
- 老司機帶你深入理解 Laravel 中介軟體(全域性中介軟體)Laravel
- 定製.NET 6.0的Middleware中介軟體
- ASP.NET Core 中介軟體(Middleware)(一)ASP.NET
- 深入理解洋蔥模型中介軟體機制模型
- 深入理解阿里分散式訊息中介軟體阿里分散式
- 理解Express中介軟體Express
- Redux 中介軟體的實現原理Redux
- 聊聊 Redux 和 Koa 的中介軟體Redux
- 從原始碼理解Redux和Koa2的中介軟體機制原始碼Redux
- 優雅的redux非同步中介軟體 redux-effectRedux非同步
- 深入理解reduxRedux
- 簡單介紹redux的中介軟體Redux
- 深入理解redux之從redux原始碼到react-redux的原理Redux原始碼React
- 中介軟體之訊息中介軟體-pulsar
- 史上最全redux,react-redux,中介軟體機制講解ReduxReact
- 深入解析Laravel的中介軟體Laravel
- 深入淺出理解ReduxRedux
- Redux 進階 -- 編寫和使用中介軟體Redux
- 中介軟體理解和誤區
- 「Go框架」深入理解web框架的中介軟體執行機制Go框架Web