中间件的作用
- 不使用中间件时,数据的修改流程:
- 每当我们调用dispatch方法的时候,传递给dispatch的实参action通知对象,就会立即reducer函数接收,并执行reducer函数体内的代码,达到修改数据的目的。

- 使用中间件时,数据的修改流程:

由上图我们可以知道,如果使用了中间件,则从我们发起dispatch开始,传入其中的action 对象,并不是直接交给reducer处理的,而是先经过了若干中间件链式处理过后,最后再由 reducer处理。所以我们可以变相的认为redux中间就是强化dispatch方法的一种机制
中间件的优势
在使用redux管理状态时候,可能会对触发action的过程,即dispatch有一些扩展的需求,redux提供了中间件机制来让开发者可以扩展dispatch。
比如,我们希望每次更新状态时候可以把更新之前的状态、action和更新之后的状态打印出来,这样可以方便地对应用进行调试和排查。
再比如,我们希望支持异步action,即dispatch可以传一个函数,函数中可以进行异步操作,异步更新状态(这个需求在调用接口获取数据的业务场景很常见)。
常用redux中间件
- redux-logger:每次dispatch触发数据更新的时候,在控制台打印数据变化前后的值,该中间件只会在开发环境会用,生产环境不会用
- redux-saga:用于管理redux异步操作的中间件
- redux-thunk:用于管理redux异步操作的中间件
redux-logger
安装
$ yarn add redux-logger
配置
在创建store的时候配置redux中间件
配置好redux-logger之后,每次dispatch函数触发的时候就会打印日志了。import { createStore,applyMiddleware } from 'redux'import logger from 'redux-logger'import reducer from './reducers/index';const store = createStore(reducer,applyMiddleware(logger));
redux-saga
安装
$ yarn add redux-saga
使用
redux-saga处理异步的流程大致为:
dispatch派发一个异步任务的actionaction中的type被redux-saga监听了——>监听函数(里面包含异步任务)触发——>监听函数中的异步任务处理完之后,最终会再派发一个同步的action//sagas/index.jsimport {put,takeEvery,delay} from 'redux-saga/effects';function * test({payload}){yield delay(1000);//延时1syield put({type:'add',payload})//派发同步action,这个action会给到reducer(这里的put就是dispatch)}export default function* index(){//asyncAdd这个type被redux-saga监听了,一旦被派发,则监听函数test会自动执行yield takeEvery("asyncAdd",test);}//如果项目功能复杂也可对sagas进行模块拆分 然后利用all方法进行合并
reducer接受action,合并返回新的数据——>数据更新function reducer(state={num:0},action){switch(action.type){case 'add':return {...state,num:state.num + aciton.payload}default:return state;}
配置
import {createStore,applyMiddleware} from 'redux';import createSgaMiddleware from 'redux-saga';import reducer from './reducers/index';import rootSaga from './sagas/index';const sagaMiddleware = createSgaMiddleware();export default createStore(reducer,applyMiddleware(sagaMiddleware));sagaMiddleware.run(rootSaga)
redux-thunk
让dispatch可以接受函数为参数(本来dispatch只能接受一个action对象为参数), 在函数内部可以写异步代码
安装
$ yarn add redux-thunk
配置
```javascript import { legacy_createStore, combineReducers, applyMiddleware } from ‘redux’; import thunk from ‘redux-thunk’; import logger from ‘redux-logger’;
const reducer = combineReducers({ counter: countReducer, cart: cartReducer })
export const store = legacy_createStore(reducer, applyMiddleware(logger, thunk));
<a name="NdgVf"></a>#### 使用一旦遇到异步,则可以把`dispatch`接受的`action`对象变成函数,异步任务就放到函数里面去处理。不过,为了定制参数,我们一般还要在外面再套一层函数。```javascriptimport React from 'react'import { useSelector, useDispatch } from 'react-redux';import { asynAddA } from '../../../store';export default function AsyncCounter () {const dispatch = useDispatch()const count = useSelector((state) => {return state.counter.count});function add () {dispatch({type: 'add',payload: 2,});}function asyncAdd () {// dispatch((next)=>{// //next参数其实就是dispatch,在底层传入的// setTimeout(()=>{// next({// type: 'add',// payload:2,// })// },2000);// });// dispatch(asynAddA);dispatch(asyncAddA(3));//传递参数}return (<div>AsyncCounter {count}<button onClick={add}>add</button><button onClick={asyncAdd}>async add</button></div>)}//store/index.js//为了方便传递参数,所有需要在外面套一层函数export const asyncAddA = (n) => (dispatch) => {setTimeout(() => {dispatch({type: 'add',payload: n,})}, 2000);}
