[三元学Redux]Redux中间件(thunk+saga应用)

1、什么是Redux的中间件?

所谓中间件,必定是处于两个事物的中间,那么什么是Redux中间件呢?ios

回顾一下Redux的工做流程:chrome

Redux的中间件,处于Action和Reducer之间,将中间某个过程拦截一下,进行一些处理再继续正常执行,这就是中间件的功能。

那为何要用到Redux中间件呢?npm

对于异步请求的代码,咱们最好将它们放到Redux中间件里面。redux

当项目复杂到必定规模的时候,咱们但愿让各个模块尽量的实行单一职责,好比React做为一个视图层的框架就只负责渲染,数据的事情通通交给Redux来处理,此时,相对于把异步请求的Ajax代码放到写到组件的componentDidMount生命周期钩子函数,其实交给Redux是一种更好的选择。另外,交给Redux,一方面可以作到不一样组件的接口复用,另外一方面方便于测试,单纯去测试一些异步代码比测试一个React组件的生命周期函数会更加容易。 然而Redux里面dispatch的过程当中只容许传递对象,而不容许传递函数。因而,redux-thunk便应运而生。axios

2、Redux-thunk实现异步更新state

npm install redux-thunk --save
复制代码

首先在项目中启用redux-thunk网络

//src/store/index.js
import {createStore, applyMiddleware, compose} from 'redux';
import reducer from './reducer';
import thunk from 'redux-thunk'
import TodoSagas from './sagas'

//须要同时激活redux-devtools的chrome插件,下面是激活代码
//兼容代码在redux-devtools的文档下拿过来照着用便可
const composeEnhancers =
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(applyMiddleware(thunk))
//建立store
const store = createStore(
  reducer,
  enhancer
)

export default store;
复制代码
//src/store/actionCreators.js
//如下为getTodoList部分
export const getTodoList = () => {
  return (dispatch) => {
    axios.get('xxx').then((res) => {
      const data = res.data.list
      //建立action
      const action = initListAction(data)
      //至关于store.dispatch
      //其实redux-thunk给当前返回函数中添加的第一个默认参数就是store的dispatch方法
      dispatch(action)
    })
  }
}
复制代码
//App.js
  componentDidMount() {
    // axios.get('xxx').then((res) => {
    // const data = res.data.data
    // const action = initListAction(data)
    // store.dispatch(action)
    // })
    //将以上代码放进Redux,效果相同
    const action = getTodoList()
    store.dispatch(action)
  }
复制代码

所以,redux-thunk实际上是拦截了store的dispatch方法,Redux中store.dispatch本来是不能传一个函数进去的,可是redux-thunk让dispatch拥有的接受函数参数的能力。具体来讲,若是dispatch方法中传递的是一个对象,那么直接按照正常的Redux工做流来运行,但若是是一个函数,那么直接执行它,并把store.dispatch这个方法看成第一个参数传进这个函数。app

3、Redux-saga实现异步更新state

redux-saga也是Redux中处理异步函数的中间件。框架

npm install redux-saga --save
复制代码

首先在项目中启动redux-saga:异步

//src/store/index.js
import {createStore, applyMiddleware, compose} from 'redux';
import reducer from './reducer';
import createSagaMiddleware from 'redux-saga'
import TodoSagas from './sagas'
//建立中间件
const sagaMiddleware = createSagaMiddleware()
//须要同时激活redux-devtools的chrome插件,下面是激活代码
const composeEnhancers =
  typeof window === 'object' &&
  window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
    window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;

const enhancer = composeEnhancers(applyMiddleware(sagaMiddleware))
//建立store
const store = createStore(
  reducer,
  enhancer
)
//启动中间件
sagaMiddleware.run(TodoSagas)

export default store;
复制代码
//sagas.js
import { takeEvery, put } from 'redux-saga/effects'
import { GET_INIT_LIST } from './actionTypes';
import { initListAction } from './actionCreators';
import axios from 'axios'
function* getInitList() {
  try {
    const res = yield axios.get('xxx')
    //拿到Ajax数据后,经过initListAction建立action对象
    //注意: 这是另外一个action:INIT_LIST_ACTION,直接改变state中的list的值
    const action = initListAction(res.data.list)
    //put至关于dispatch这个新的action
    yield put(action)
  }catch(e) {
    console.log('网络请求失败')
  }
}
//导出的mySaga须要写成一个Generator函数,异步处理函数getInitList也应是Generator函数
function* mySaga() {
  //拦截GET_INIT_LIST这个action
  yield takeEvery(GET_INIT_LIST, getInitList);
}

export default mySaga
复制代码
//App.js
  componentDidMount() {
    const action = getInitList()
    store.dispatch(action)
  }
复制代码

因此你可以看到,在redux-saga当中的处理思路是: 先抛出一个相似于信号灯的action,redux-saga看到了这个信号灯,拦截下来,而后执行响应的异步函数,在这个异步函数拿到数据后,执行真正要更新state的action。在这个过程当中,做为信号灯的action在reducer中并无具体关于state的逻辑编写,而仅仅是给redux-saga发一个信号而已。函数

关于redux中间件一点小小的总结,但愿对你们有所帮助。

相关文章
相关标签/搜索