使用redux-thunk 中间件实现ajax数据请求

redux-thunk 是一个比较流行的 redux 异步 action 中间件,比如 action 中有 setTimeout 或者通过 axios 通用远程 API 这些场景,那么就应该使用 redux-thunk 了。redux-thunk 统一了异步和同步 action 的调用方式,把异步过程放在 action 级别解决,对 component 没有影响。换言之,中间件都是对store.dispatch()的增强

安装redux-thunk依赖

npm install redux-thunk
cnpm i redux-thunk
yarn add redux-thunk

引入redux-thunk

import thunk from 'redux-thunk'

配置redux-thunk和redux-devtools一起使用

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),
);

const store = createStore(
    reducer,
    enhancer
)

export default store 

applyMiddleware是redux的一个原生方法,将中间件放入一个数组,以此执行。扩展(redux-middleware)[https://redux.js.org/advanced/middleware]

使用thunk的ajax请求

配置好了redux-thunk就可以将 componentDidMount里的异步请求移除,没有用redux-thunk之前,actionCreators.js 中export的都是一个action对象。用了redux-thunk之后可以返回一个函数了, 可以返回一个异步请求

// actionCreators.js
export const getTodoList = () => {
    return (dispatch) => {
        axios.get('http://localhost:8000/list').then((res) => {
           const listData = res.data.data.list
           const action = initListAction(listData)
           dispatch(action)
        })
    }
}


// Todolist.js
import { 
    getTodoList
} from './store/actionCreator'

componentDidMount() {
    this.props.handleInitList()
}

const mapDispatchToProps = (dispatch) => {
    return {
        handleInitList() {
            const action = getTodoList()
            dispatch(action)
        }
    }
}

redux-thunk的工作流程(原理)

一般情况下store接受的action都是action对象,使用了redux-thunk后,store可以接收函数的action,接收到并且直接执行,这样就发出了一个异步请求。请求返回结果后,需要将数据告知store,进行数据更新,此时可以再发送一个action,来更新store数据。

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

export const getTodoList = () => {
    // store 在执行函数的时候,会传一个dispatch
    return (dispatch) => {
        axios.get('http://localhost:8000/list').then((res) => {
           const listData = res.data.data.list
           // 拿到数据后 通过dispatch一个action, 告知store数据更新了 
           const action = initListAction(listData)
           dispatch(action)
        })
    }
}

异步主要用 middleware,thunk 只是一个可以让你在一个 dispatch 中能够继续 dispatch 的中间件。后续会有redux-sage的介绍。

redux-thunk的源码解析

function createThunkMiddleware(extraArgument) {
      return ({ dispatch, getState }) => next => action => {
                    // 这里判断action是否是function, 若是就改写dispatch, 直接执行该函数,并且将dispath、getState传给该函数
            if (typeof action === 'function') {
              return action(dispatch, getState, extraArgument);
            }

            return next(action);
      };
}

const thunk = createThunkMiddleware();
thunk.withExtraArgument = createThunkMiddleware;

export default thunk;

如果传入的参数是函数,则执行函数。否则还是跟之前一样dispatch(PlainObject).

为什么要使用redux-thunk

为什么最好不要把异步请求放到生命周期里,是因为随着业务量的增大,会有越来越多的异步请求,生命周期会异常庞大。建议还是把异步请求放到一个actionCreators里去管理。

将异步请求放到actionCreators里去管理,比放到生命周期里, 更好的做自动化测试,具体是怎么好做的呢?后续更新!

你可能感兴趣的:(使用redux-thunk 中间件实现ajax数据请求)