Redux核心概念
Redux的核心概念其實很簡單:將需要修改的state都存入到store里憋他,發(fā)起一個action用來描述發(fā)生了什么,用reducers描述action如何改變state tree 亲铡。創(chuàng)建store的時候需要傳入reducer才写,真正能改變store中數(shù)據(jù)的是store.dispatch API。
Reducer:純函數(shù)奖蔓,只承擔計算 State 的功能赞草,不合適承擔其他功能,也承擔不了吆鹤,因為理論上厨疙,純函數(shù)不能進行讀寫操作。(功能有限 需要中間件)
Action:存放數(shù)據(jù)的對象疑务,即消息的載體沾凄,只能被別人操作梗醇,自己不能進行任何操作。
Redux中間件
dispatch一個action之后撒蟀,到達reducer之前叙谨,進行一些額外的操作,就需要用到middleware牙肝。 你可以利用 Redux middleware 來進行日志記錄唉俗、創(chuàng)建崩潰報告、調(diào)用異步接口或者路由等等配椭。
換言之虫溜,中間件都是對store.dispatch()的增強。
不難發(fā)現(xiàn):
- 不使用middleware時股缸,在dispatch(action)時會執(zhí)行rootReducer衡楞,并根據(jù)action的type更新返回相應的state。
- 而在使用middleware時敦姻,簡言之瘾境,middleware會將我們當前的action做相應的處理,隨后再交付rootReducer執(zhí)行镰惦。
https://cn.redux.js.org 中文官方文檔
注意迷守,不太需要研究如何寫中間件,因為:常用的中間件都有現(xiàn)成的旺入,只要引用別人寫好的模塊即可兑凿。
故 只要按照中間件官方提供的規(guī)定格式 實現(xiàn)程序,并應用到中間件方法茵瘾,那么礼华,在執(zhí)行一個action的時候,就會成功調(diào)用中間件拗秘。
中間件 的軟件工程定義是什么
中間件不是產(chǎn)出最終結果圣絮,而是 處理一些 程序流程中間 的操作。
作用:中間件常做一些 業(yè)務邏輯之間 的數(shù)據(jù)轉換雕旨,讓開發(fā)者不需要關注底層邏輯扮匠,而專心于當前的開發(fā)。
Middleware makes it easier for software developers to implement communication and input/output, so they can focus on the specific purpose of their application. -- Wiki
比如 ajax==>json(亂的數(shù)據(jù))==>service轉換(中間件)==>UI(整齊的數(shù)據(jù))
示例:使用redux中間件
applymiddleware將一堆函數(shù)封裝成一個函數(shù)凡涩,這些函數(shù)的執(zhí)行順序由next傳遞餐禁。
import { createStore, applyMiddleware } from 'redux';
// 中間件為 高階函數(shù):1.函數(shù)做參數(shù) 2.return出的也只是函數(shù)
const logger1 = store => next => action => { //柯里化:next函數(shù) 在store的源碼中被一番處理后返回(高階函數(shù)),新next再接收參數(shù)action
console.log('current dipatch' + JSON.stringify(action));
next(action);
};
const logger2 = store => next => action=> {
next(action);
};
const logger3 = store => next => action=> {
next(action);
};
const enhancer = applyMiddleware(logger1, logger2, logger3); //enhancer為一個函數(shù),否則報錯
const reducer = (state, action) => state;
const store = createStore(reducer, {}, enhancer); //{}為初始化的store數(shù)據(jù)
store.dispatch({type:1});
store.dispatch({type:2});
store.dispatch({type:3});
//createStore第3個參數(shù)enhancer若存在突照,將先執(zhí)行enhancer內(nèi)的中間件邏輯后再dispatch帮非,而后才執(zhí)行reducer的邏輯。
//可見中間件增強enhance了reducer&createStore
詳解JS函數(shù)柯里化 - 簡書
柯里化:多參函數(shù)->單參函數(shù)
就是把一個由多個參數(shù)的函數(shù),寫成 多個函數(shù)嵌套末盔,每個函數(shù)只有1個參數(shù)筑舅,每個函數(shù)返回下一個函數(shù)。
redux不用中間件 的代碼書寫順序
action ==> dispatch ==> reducer ==> nextState
redux用中間件 的代碼書寫順序 (middleware是在dispatch和reducer之間起作用)
action ==> middleware ==> dispatch ==> reducer ==> nextState
如何自己寫一個中間件
在官方的示例中陨舱,有一個logger實現(xiàn)的示例
const logger = store => next => action =>{
console.log('prev state',store.getState()) //獲取狀態(tài)數(shù)據(jù)
console.log('dispatch',action);
let result = next(action);
console.log('next state',store.getState());
return result;
}
從這個示例可以看出翠拣,實現(xiàn)一個中間件需要做一下幾件事情:
- 三層函數(shù)包裝:第一層傳入store,第二層傳入下一個中間件next游盲,第三層傳入此次執(zhí)行的action误墓;
- 在最內(nèi)層的函數(shù)實現(xiàn)中,需要調(diào)用next中間件益缎,并返回結果谜慌。
參考 http://www.reibang.com/p/dbe65d95c77b
applyMiddleware與redux中間件的原理
封裝改造store.dispatch,將其指向中間件莺奔,以實現(xiàn) 在dispatch和reducer之間 處理action數(shù)據(jù)的邏輯欣范。
大體原理如下
// 儲存原來的dispatch
const dispatch = store.dispatch;
// 改變dispatch指向
store.dispatch = dispatchPre; //指向中間件
// 重命名
const next = dispatch;
參考 源碼分析 https://segmentfault.com/a/1190000018347235
redux-thunk中間件+applymiddleware 實現(xiàn) 能異步的reducer
Redux store 默認僅支持同步數(shù)據(jù)流。 使用 thunk中間件 可以幫助在 Redux 應用中實現(xiàn) 異步的reducer令哟。比如恼琼,action中 有setTimeout、ajax/fetch調(diào)用遠程API 這些場景屏富,就可用thunk中間件晴竞。
可以將 thunk中間件 看做 store 的 dispatch() 方法的封裝器。我們可以使用 thunk的"action creator結構函數(shù)"來派遣 函數(shù)或Promise狠半,而不是返回 action 對象,颓鲜,具體如下。
背景: 沒有 thunk 的話典予,默認地是同步派遣。雖然乐严,同步機制 依然可以從React組件發(fā)出API調(diào)用(例如使用componentDidMount()生命周期方法發(fā)出這些請求)瘤袖,但在Redux應用中,同步派遣 難以實現(xiàn)以下兩點:1.可重用性(思考下合成) 2.可預測性昂验,只有 action creator 可以是狀態(tài)更新的單一數(shù)據(jù)源捂敌。
直接將thunk中間件引入,放在applyMiddleware方法之中既琴,傳入createStore方法占婉,就完成了store.dispatch()的功能增強。即可以在reducer中進行一些異步的操作甫恩。
import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import reeducers from '....';
const store = createStore(
reducers,
applyMiddleware(thunk, logger) //thunk本身是一個中間件逆济,logger也是一個中間件,還可以放更多
); //thunk的實例被傳遞給Redux的applyMiddleware() enhancer函數(shù)
其實applyMiddleware就是Redux的一個原生方法,將所有中間件組成一個數(shù)組奖慌,依次執(zhí)行抛虫。
中間件多了可以當做參數(shù)依次傳進applyMiddleware。
Redux-thunk可以讓reducer直接使用 異步操作简僧,通過把 異步的action creator 放入reducer中建椰。
如下就是個action creator,它必須返回一個函數(shù)(而非對象)岛马,可以是異步函數(shù)
export function addCount() {
return {type: ADD_COUNT}
}
export function addCountAsync() {
return dispatch => {
setTimeout( () => {
dispatch(addCount())
},2000)
}
}
addCountAsync函數(shù)就返回了一個函數(shù)棉姐,將dispatch作為函數(shù)的第一個參數(shù)傳遞進去,在函數(shù)內(nèi)進行異步操作就可以了啦逆。
該部分參考如下
redux-thunk的源碼分析和更多操作 見
Redux中間件之redux-thunk使用詳解 - 簡書 源碼分析
Redux-thunk中間件 - 簡書 使用方法 如何寫異步ajax的fetch+promise接收數(shù)據(jù)
全文參考
阮一峰 -- Redux 入門教程(二):中間件與異步操作 (涉及redux-thunk redux-promise) https://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_two_async_operations.html