????在最開始編寫項(xiàng)目代碼的時(shí)候,ajax請求放在生命周期函數(shù)componentDidMount()中,但是隨著代碼量增加,componentDidMount()中有越來越多的邏輯,因此引入中間件middleware,將ajax請求做統(tǒng)一管理,復(fù)雜的邏輯放在action處理對之后維護(hù)以后以自動化測試都提供了很大的幫助。
何為中間件?
It provides a third-party extension point between dispatching an action, and the moment it reaches the reducer. People use Redux middleware for logging, crash reporting, talking to an asynchronous API, routing, and more.
Redux中間件在派發(fā)action以及它到達(dá)reducer之間提供了第三方擴(kuò)展。使用Redux中間件進(jìn)行日志記錄、崩潰報(bào)告、與異步API交談、路由等等。
????簡單來說middleware指的是action和store之間,對dispatch的封裝和升級,使用middleware之后,action既可以是一個(gè)對象,也可以是一個(gè)函數(shù)
增加中間件后的數(shù)據(jù)流
Redux標(biāo)準(zhǔn)流程
1.頁面派發(fā)一個(gè)action
2.通過dispatch方法派發(fā)給store(action是一個(gè)對象)
3.store接收到action,連同之前的state傳給reducer
4.reducer返回一個(gè)新的數(shù)據(jù)給store
5.store去改變自己的state
增加middleware之后,Data Flow是下圖這樣的

????使用Redux中間件后流程,調(diào)用dispatch()方法,根據(jù)參數(shù)的不同,執(zhí)行不同的流程。如果參數(shù)是對象就把這個(gè)對象直接傳遞給store,如果參數(shù)是函數(shù),就先執(zhí)行這個(gè)函數(shù),執(zhí)行之后如果需要調(diào)用store,那這個(gè)函數(shù)再去調(diào)用store。
Redux處理異步流
- redux-thunk
1.安裝redux-thunk
yarn add redux-thunk
- 修改
store的配置
import { createStore, applyMiddleware, compose } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'
const composeEnhancers =
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(
applyMiddleware(thunk),
// other store enhancers if any
);
const store = createStore(reducer, enhancer);
export default store
// https://github.com/zalmoxisus/redux-devtools-extension
3.在action中編寫寫異步的代碼(action可以返回一個(gè)函數(shù)啦??)
export const getTodoList = () => {
return () => {
axios.get('http://mock-api.com/Rz317OnM.mock/api/todolist')
.then((res) => {
console.log(res.data)
})
.catch( () => {alert('error')})
}
}
4.通過reducer更新store中的數(shù)據(jù)
export const getTodoList = () => {
return (dispatch) => {
axios.get('http://mock-api.com/Rz317OnM.mock/api/todolist')
.then((res) => {
console.log(res.data)
const data = res.data
const action = initListAction(data)
dispatch(action)
})
.catch( () => {alert('error')})
}
}
5.Todolist.js獲取數(shù)據(jù)
import { getInputChangeAction, getAddItemAction, getDeleteItemAction, getTodoList } from './store/actionCreators'
componentDidMount () {
const action = getTodoList()
store.dispatch(action)
console.log(action)
}
- redux-saga
適用于非常大型復(fù)雜的項(xiàng)目
github:https://github.com/redux-saga/redux-saga
1.安裝redux-saga
yarn add redux-saga
2.配置store/index.js
import { createStore, applyMiddleware, compose } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducer'
import todoSagas from './sagas'
const sagaMiddleware = createSagaMiddleware()
const composeEnhancers =
typeof window === 'object' &&
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware));
const store = createStore(reducer, enhancer);
sagaMiddleware.run(todoSagas)
export default store
3.創(chuàng)建sagas.js文件
//sagas文件一定要有 generator 函數(shù)
function* mySaga() {
}
export default mySaga;
4.修改Todolist.js中獲取數(shù)據(jù)的方法
componentDidMount () {
const action = getInitList()
console.log(action)
store.dispatch(action)
}
5.補(bǔ)充邏輯
actionTypes.js
export const GET_INIT_LIST = 'get_init_list'
actionCreator.js
export const getInitList = () => ({
type: GET_INIT_LIST
})
sagas.js
import { takeEvery, put } from 'redux-saga/effects'
import { GET_INIT_LIST } from './actionTypes'
import axios from 'axios'
import { initListAction } from './actionCreators'
function* getInitList() {
try{
const res = yield axios.get('http://mock-api.com/Rz317OnM.mock/api/todolist')
const action = initListAction(res.data)
yield put(action)
} catch(e) {
console.log('網(wǎng)絡(luò)請求失敗')
}
}
// generator 函數(shù)
function* mySaga() {
yield takeEvery(GET_INIT_LIST, getInitList);
}
export default mySaga;
(完)