到底什么是Redux中间件——基于Redux-thunk和Redux-saga理解分析

       前面的文章中,我们介绍过,React在发送Ajax等异步请求的时候,我们应该将异步请求的逻辑放在componentDidMount钩子函数中。但是有一个问题,当一个组件中有很多个异步请求操作,都放在这个钩子函数中,那么这个钩子函数会显得很臃肿,该怎么解决这个问题了? 在React中我们可以通过引入中间件的机制来解决这个问题。常用的中间件有redux-thunkdedux-saga

一、Redux中的中间件

       首先,我们来看一下,Redux中的中间件是什么?如下图:

Redux中的中间件

React中的中间件位于ActionStore之间,中间件是对dispatch方法的封装和升级
       下面我们就以处理异步请求的操作来演示Redux中间件的使用方式。对于处理异步操作,我们常用的中间件有redux-thunkdedux-saga。至于两个中间件的差别,我们在具体讲解完这两个中间件后在进行说明。

二、Redux中的中间件——Redux-chunk

       在之前文中《React数据管理工具Redux流程分析及基础使用实践》,我们在/src/store/actionCreators.js中定义action的时候,要求各函数最后返回的必须是一个对象,但是通过中间件redux-chunk的处理,可以允许actionCreators返回函数,我们可以在这个函数中执行我们的异步代码,执行完成之后返回对象。具体流程如下:
       1、安装Redux-chunk

yarn add redux-thunk

       2、配置Redux-chunk环境
       /src/store/index.js

import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import reducer from './reducer'

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ?   
window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose

const enhancer = composeEnhancers(
    applyMiddleware(thunk)
)

const store = createStore(reducer, enhancer)
export default store

       此配置过程,可以查文档,也可以直接copy此处代码。
       3、设置返回值为函数的antion
       /src/store/actionCreators.js
       这块是redux-thunk的核心,也是我们最应该注意的地方。

import { INIT_LIST_ACTION } from './actionTypes'

export const initListAction = (data) => ({
    type: INIT_LIST_ACTION,
    data
})

export const getTodoList = () => {
    return (dispatch) => {
        setTimeout(function(){
            let data = ['learning react', 'learning redux'] 
            const action = initListAction(data)
            dispatch(action)
        })
    }
}

       /src/store/actionTypes.js

export const INIT_LIST_ACTION = 'init_list_action'

       4、在reducer中处理数据

import { INIT_LIST_ACTION } from './actionTypes'
export default (state = defaultState, action) => {
  ...
  if(action.type === INIT_LIST_ACTION){
        const newState = JSON.parse(JSON.stringify(state))
        newState.list = action.data
        return newState
    }
  ...
}

       5、在组件中componentDidMount钩子函数中调用该异步请求
       /src/TodoList.js

componentDidMount(){
        const action = getTodoList()
        store.dispatch(action)
    }

三、Redux中的中间件——Redux-saga

       我们在使用Redux-thunk中间件的时候,是将异步的操作放在ActionCreators中的。而Redux-saga是将异步操作抽离到单独的文件中,通过调用generator函数执行。
       1、安装Redux-saga

yarn add redux-thunk

       2、配置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()
const composeEnhancers = 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、创建saga文件

import { takeEvery, put } from 'redux-saga/effects'
import { GET_INIT_LIST } from './actionTypes'
import { initListAction } from './actionCreator'

function* getInitList(){
    try {
        const data = ['learning react','learning redux']
        const action = initListAction(data)
        yield put(action)
    } catch (e) {
        console.log('network error')
    }
}

function* mySaga(){
    yield takeEvery(GET_INIT_LIST, getInitList)
}

export default mySaga

       4、定义actionCreators中的action
/src/store/actionCreators.js

export const getInitList = (data) => ({
    type: GET_INIT_LIST
})

       5、创建actionTypes类型

export const GET_INIT_LIST = 'get_init_list'

       6、使用Redux-saga
/src/TodoList.js

import { getInitList } from './store/actionCreator'

componentDidMount(){
    const action =  getInitList()
    store.dispatch(action)
}

       使用Redux-saga,在组件中通过store.dispatch(action)提交action后,会在/src/store/sagas.js中的generator函数中监测到,我们在在sagas文件中完成我们的异步请求操作。在经过sagas处理之后,我们就可以在reducer中继续执行我们熟悉的操作了——修改数据。

import { GET_INIT_LIST } from './actionTypes'

export default (state = defaultState, action) => {
  ...
  if(action.type === GET_INIT_LIST){
        const newState = JSON.parse(JSON.stringify(state))
        newState.list = action.data
        return newState
  }
  ...
}

       项目目录结构如下图:


项目目录结构

       Redux-saga和Redux-thunk解决的问题一致,但是实现方式有所不同,saga把异步请求的操作全部放在saga文件中,而thunk只是来原来的基础上,对actionCreator进行一些操作(执行函数)。一般来说,saga用于大型复杂项目,其API很多,拓展性极好。

你可能感兴趣的:(到底什么是Redux中间件——基于Redux-thunk和Redux-saga理解分析)