【学习笔记 】React ⑦ 使用Redux中间件处理异步流
在最开始编写项目代码的时候,ajax
请求放在生命周期函数componentDidMount()
中,但是随着代码量增加,componentDidMount()
中有越来越多的逻辑,因此引入中间件middleware
,将ajax
请求做统一管理,复杂的逻辑放在action
处理对之后维护以后以自动化测试都提供了很大的帮助。
何为中间件?
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中间件在派发action以及它到达reducer之间提供了第三方扩展。使用Redux中间件进行日志记录、崩溃报告、与异步API交谈、路由等等。
简单来说middleware
指的是action
和store
之间,对dispatch
的封装和升级,使用middleware
之后,action
既可以是一个对象,也可以是一个函数
增加中间件后的数据流
Redux标准流程
1.页面派发一个action
2.通过dispatch方法派发给store(action是一个对象)
3.store接收到action,连同之前的state传给reducer
4.reducer返回一个新的数据给store
5.store去改变自己的state
增加middleware
之后,Data Flow是下图这样的
使用Redux
中间件后流程,调用dispatch()
方法,根据参数的不同,执行不同的流程。如果参数是对象就把这个对象直接传递给store
,如果参数是函数,就先执行这个函数,执行之后如果需要调用store
,那这个函数再去调用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
可以返回一个函数啦🤣)
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
中的数据
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
获取数据
import { getInputChangeAction, getAddItemAction, getDeleteItemAction, getTodoList } from './store/actionCreators'
componentDidMount () {
const action = getTodoList()
store.dispatch(action)
console.log(action)
}
- redux-saga
适用于非常大型复杂的项目
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.创建sagas.js文件
//sagas文件一定要有 generator 函数
function* mySaga() {
}
export default mySaga;
4.修改Todolist.js中获取数据的方法
componentDidMount () {
const action = getInitList()
console.log(action)
store.dispatch(action)
}
5.补充逻辑
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('网络请求失败')
}
}
// generator 函数
function* mySaga() {
yield takeEvery(GET_INIT_LIST, getInitList);
}
export default mySaga;
(完)