Redux很早前看過原始碼,不得不說Redux是一個有用的架構,接觸過Redux對於之後理解React-Redux有很大的幫助。最近學習了一段時間後打算重新學習下,一方面為了總結和歸納,另一方面分享給大家,如果有什麼不足之處希望各位大牛的糾錯和指正。本文主要包含如下幾個分析點:
- applyMiddleware
- compose
- thunk中介軟體
// 該檔案的核心函式部分共傳入了三個引數
// reducer, preloadedState, enhancer
function createStore(reducer, preloadedState, enhancer){
...
if (typeof enhancer !== 'undefined') {
return enhancer(createStore)(reducer, preloadedState)
}
...
}
複製程式碼
createStore
方法的作用是用來建立一個倉庫來存放state,subscribe,reducer以及dispatch,state用來存放資料的地方,通過store.getState()來獲取;subscribe用來加入監聽函式,當頁面資料改變的時候會進行觸發,dispatch用來派發action,根據不同的型別匹配不同的reducer,繼而進行state資料的更新,具體可以參考阮一峰老師的部落格
Redux 入門教程。
其中enhancer
函式的作用顧名思義就是用來擴充套件加強的,這個函式的存在使得可以隨意的加入早就想要的中介軟體,從而更加方便快捷,這裡的加強函式主要是applyMiddleware
。
applyMiddleware
這裡使用連續箭頭函式,簡單明瞭更重要的一點是形成了閉包,閉包的存在使得內部的變數可以很自由的訪問外部被多個return巢狀的變數, 從而使得每個中介軟體都獲得middlewareAPI引數,引用外部的dispatch變數,這樣避免瞭如果存在一箇中介軟體修改了dispatch導致後面一系列的問題。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: (action) => dispatch(action) // 通過閉包引用外部的dispatch變數
}
// 將middlewareAPI傳入中介軟體,使得每個中介軟體都獲得{getState,dispatch}引數,而由於閉包的原因,我們就可以在中介軟體當中獲取最新的store以及引用外部更新的dispatch變數。
// @return 返回包含(next) => (action) => {....}的陣列
chain = middlewares.map(middleware => middleware(middlewareAPI))
// 建立增強功能的dispatch
dispatch = compose(...chain)(store.dispatch)
return {
...store,
dispatch
}
}
}
複製程式碼
thunk中介軟體
以thunk中介軟體為例,當需要派發的action是非同步函式而不是物件的時候需要這個中介軟體,則此時chain即為[(next)=>(action)=>{...}, ....], 如果action為函式則直接執行該函式,並且傳入dispatch和getSate這兩個引數,否則執行next方法直到最後next函式為dispatch進行action派發。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;
複製程式碼
compose
理解compose方法首先需要了解reduce,reduce()方法接收一個函式作為累加器,陣列中的每個值(從左到右)開始縮減,最終計算為一個值,所以最終的形式是a(b(c(d...(...args))))
。
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)))
}
複製程式碼
之前chain返回包含(next) => {...}的thunk,logger中介軟體陣列,從而得到a_middleware方法裡的next方法就是b_middleware,b_middleware方法裡的next方法是c_middleware,以此類推,根據applyMiddleware.js
中compose(...chain)(store.dispatch)
以及chain返回值
可以知道, 最後的next引數是dispatch,大概步驟如下:
- 第一步:當我們把store.dispatch傳入c_middleware時,這時就把store.dispatch傳給了
c_middleware的next變數,返回一個
(action)=>{next=store.dispatch}
[1]函式; - 第二步:接下來就是把
[1]
傳給b_middleware的中介軟體的next,這時候中介軟體b_middleware內部的next就變成(action)=>{[1]}
[2], 當執行b_middleware的時候,會進入c_middleware; - 第三步:接下來就是把
[2]
的結果傳遞給a_middleware, (action)=>(action)=>{[1]}傳遞給a-middleware的next變數,當執行a_middleware的時候會進入b_middleware。
從下面大概例子可以看出disatch: (...args) => dispatch(...args)
的好處,dispatch隨時隨地隨著dispatch = compose(...chain)(store.dispatch)
更新而更新,從而當傳入為方法的時候,也不會忽略其他中介軟體,再次dispatch的時候會流過所有thunk之後的中介軟體。
a_middleware(b_middleware){
...
b_middleware = next = (action) => {
dispatch = (action) => {
dispatch = (action)=>{store.dispatch函式}
(action) => {dispatch}
}
return (action) => {dispatch}
}
return next(action)
...
}
b_middleware(c_middleware){
...
c_middleware = next = (action) => {
dispatch = (action)=>{store.dispatch函式}
return (action) => {dispatch}
}
return next(action)
...
}
c_middleware(store.dispatch){
return (action)=>{store.dispatch函式}
}
複製程式碼
總結
1.首先將store.getState
和store.dispatch
通過閉包的方式使得中介軟體可以訪問;
2.其次,通過compose
函式操作,對next進行賦值,使得中介軟體按順序依次執行;
3.最後,返回一個dispatch函式
,可以通過傳入action引數,使得中介軟體按順序依次執行,如果action為函式則直接執行該函式,並且傳入dispatch和getSate引數。
總之使用redux進行狀態管理極大地提高了工作效率,讓資料更好地被管理。