redux 單向數據流的由來
- Flux將應用分成四個部分;
- view 視圖層;
- Action 視圖層發出的消息;(改變store里面的數據)
- Dispatch(派發器)
- Store (數據層) : 用來存在應用的狀態(數據),一旦發生變動,就要提醒view更新頁面。
redux單向數據流:
Action
-
定義. Action 是把數據從應用(譯者注:這里之所以不叫 view 是因為這些數據有可能是服務器響應,用戶輸入或其它非 view 的數據 )傳到 store 的有效載荷。它是 store 數據的唯一來源。一般來說你會通過 store.dispatch() 將 action 傳到 store。
-
狹義的Action
let action = {type: 'ACTION_NAME',...
}
復制代碼
注意: 一般 type 的內容使用 大寫字母+下劃線 的格式.
-
廣義的Action
廣義的 action 是指在中間件的支持下,dispatch 函數可以調用的數據類型,除了普通action之外,常見的有 thunk, promise 等。我們用常用的 thunk來舉個例子
什么叫thunk函數? 具體背景見阮一峰es6標準入門一書第17章Thunk函數的含義.在javaScript中函數將多參數函數替換成單參數的版本,且只接受回調函數作為參數。 例如:
var Thunk = function(fn){return function(){var args = Array.prototype.slice.call(arguments);return function(callback){args.push(callback);return fn.apply.(this,args);}}
}var readFileThunk = Thunk(fs.readFile);readFileThunk(fileA)(callback);
復制代碼
Thunk函數版本的action:
復制代碼
(dispatch, getState) => { //在函數體內可以使用 dispatch 方法來發射其他 action//在函數體內可以使用 getState 方法來獲取當前的state
}
復制代碼
ceateStore
通過該API創建一個store對象,該對象包含四個方法;
- getState();獲取store中當前的狀態。
- dispatch(action): 分發一個action,并返回這個action,這是唯一能改變store中數據的方式。
- subscribe(listener): 注冊一個監聽者,它在store發生變化時被調用。
- replaceReducer(nextReducer): 更新當前store里的reducer, 一般只會在開發模式中調用該方法。
redux middleware
-
Redux 是一個簡單的同步數據流,當分發一個action時,reducer收到action后,更新state并通知view重新渲染。 當action發出后如果想要執行一些別的操作,該怎樣處理,也就是說action發出后沒有立即執行reducer,將redux變成異步. 這時就要借助中間件。
-
redux-middleware的數據流動.
- 中間件的由來以及原理. 中間件的思想來源于koa. 核心思想:將middleware(函數)進行組合,將當前的middleware執行一遍作為參數傳給下一個middleware去執行。
原理:
app.use((ctx, next) => {ctx.name = 'Lucy'next()
})app.use((ctx, next) => {ctx.age = 12next()
})app.use((ctx, next) => {console.log(`${ctx.name} is ${ctx.age} years old.`) // => Lucy is 12 years old.next()
})// ... 任意調用 use 插入中間件app.go({}) // => 啟動執行,最后會調用 callback 打印 => { name: 'Lucy', age: 12 }
復制代碼
ctx 參數就是 app.go 接受的對象。調用 app.go 其實會調用目標函數 app.callback,但是調用 app.callback 之前我們可以先讓參數 ctx 通過一系列的中間件,最后才會傳遞給 app.callback。
使用 app.use 插入任意中間件,中間件是一個函數,可以被傳入一個 ctx 和 next;調用 next 的時候會執行下一個中間件。如果不調用 next 會阻止接下來所有的中間件的執行,也不會執行 app.callback。
這里的app.use()就是一個實現中間件。
const app = {middleware:[],callback(){console.log(ctx);},use(fn){this.middleware.push(fn);},go(){const reducer = (next,fn,i)=> { fn(ctx,next)}this.middleware.reduceRight(reducer,this.callback.bind(this,ctx))();}
}
復制代碼
- redux的applyMiddleware的源碼.
function applyMiddle(){(next) => (reducer, initialState) => {let store = next(reducer,initialState);let dispatch = store.dispatch;let chain = [];let middlewarAPI = {getState:Store.getState,dispatch: (action) => { dispatch(action)}}chain = middlewares.map(middleware => middleware(middlewarAPI));dispatch = compose(...chain)(store.dispatch);return {...store,dispatch}}}
復制代碼
一般這樣應用middleware
const finalCreateStore = compose(applyMiddleware(...middleware)//DevTools.instrument()
)(createStore);const store = finalCreateStore(reducer);
復制代碼
middleware的一般寫法
const m1 = store => next => action => {let result = next(action);switch (action.type) {case APP_INCREMENT_LOADING:globalProgressBar.incrementLoading();break;case APP_DECREMENT_LOADING:globalProgressBar.decrementLoading();break;}return result;
};export default m1;復制代碼
注:這里的compose函數請參考app.go或者參考上章FP一節; applyMiddle其實用了2個中間件的思想; 源碼的詳細解釋: