Redux-thunk 原始碼
短短14行到底做了什麼呢XD?
開始之前我們先看一下 redux 的 applyMiddleware 做了什麼,這樣回過頭來看redux-thunk的原始碼才更清楚。
Redux API: applyMiddleware() api
Each middleware receives
Store
'sdispatch
andgetState
functions as named arguments, and returns a function. The last middleware in the chain will receive the real store’sdispatch
method as thenext
parameter, thus ending the chain. So, the middleware signature is({ getState, dispatch }) => next => action
每個 middleware 會接收 Store
的 dispatch
和 getState
functions 作為具名參數,並回傳一個 function。最後的 middleware 會接收到 store 的 dispatch 作為 next 傳入,最後結束。
這樣回頭看 redux-thunk 就相當簡單了,thunk 把宣告成 function 的 action 攔截下來在包了一層,可以想成是 closure 的應用,繼續往下傳遞,由最後我們所宣告的 function action 來執行內容,那正常的 action (我相信應該會是 object),就會由 next 直接執行 (即 dispatch )。
如果有人還是覺得一定要看一下 source code呢 …
那我們就來看R,我截去ts的部分,這樣比較乾淨一點
function applyMiddleware(...middlewares) { return (createStore) => (reducer, ...args) => {
const store = createStore(reducer, ...args);
let dispatch = () => {
throw new Error('Apply Middleware Error');
}
const middlewareAPI = {
getState: store.getState,
dispatch: (action, ...args) => dispatch(action, ...args)
}
const chain = middlewares.map(
middleware => middleware(middlewareAPI));
dispatch = compose(...chain)(store.dispatch);
return {
...store,
dispatch
}
}}
一個個來看看
let dispatch = () => {
throw new Error('Apply Middleware Error');
}
先設置如果後面dispatch 在 compose middlewares 只傳回自己時,throw error,就是 chain 為空的意思。
middlewareAPI
很 Ez,就是前面({ getState, dispatch }),要收到所準備的參數。
const chain = middlewares.map(
middleware => middleware(middlewareAPI));
每個middleware 都包裝 getState, dispatch 進入產生 middleware 陣列。
dispatch = compose(...chain)(store.dispatch);
compose 是個啥呢
function compose(...funcs) { return funcs.reduce((a, b) => (...args) => a(b(...args)))}
假設有三個 middleware 好了
m1 = ({ getState, dispatch }) => (next) => (action) => { console.log('m1'); return next(action);
}m2 = ({ getState, dispatch }) => (next) => (action) => { console.log('m2'); return next(action);
}m3 = ({ getState, dispatch }) => (next) => (action) => { console.log('m3'); return next(action);
}還記得剛剛包裝過 getState, dispatch了嗎?m1Middleware = m1(middlewareAPI);m1Middleware = (next) => (action) => { console.log('m1'); ..., return next;
}m2Middleware = (next) => (action) => { console.log('m2'); ..., return next;
}m3Middleware = (next) => (action) => { console.log('m3');
..., return next;
}
就會變成 m1Middleware(m2Middleware(m3Middleware(store.dispatch)))
log
m3 -> m2 -> m1const m1 = (next) => (action) => {console.log("m1");return next(action);}const m2 = (next) => (action) => {console.log("m2");return next(action);}const fakeDispatch = (action) => {console.log("Final Dispatch this action", action);}const fakeActionYouInput = {type: "fakeType"}m1(m2(fakeDispatch))(fakeActionYouInput);m1
m2
Final Dispatch this action { type: 'fakeType' }
本來以為可以更簡短,結果越寫越多,希望日後回來看不會一頭霧水。