本文主要介绍了在 Redux 中使用 redux-thunk 进行异步操作。

如果对 Redux 尚不熟悉,建议先看我的前一篇博客:Redux 基础教程以及结合 React 使用方式

最下方贴上了 applyMiddleware 和 redux-thunk 的实现源码,有兴趣的同学可以看一看。只能用两个字来形容:优秀


在项目中引入

  • 安装插件

    1
    $ npm install redux-thunk;
  • 在创建 store 时引入 redux-thunk

    使用 commonJs 方式引入时要注意,这样引入才可以正常使用:const thunk = require('redux-thunk').default

    1
    2
    3
    4
    5
    6
    import { createStore, applyMiddleware } from 'redux';
    import thunk from 'redux-thunk';

    // 创建 store
    // applyMiddleware,在 Redux 中使用中间件时,就需要使用 applyMiddleware() 这个函数进行包裹
    const store = createStore(reducer, applyMiddleware(thunk));
  • 在 action 中的书写方式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    // 异步请求成功需要用到的同步 action 创建函数
    function actionSuccess(msg) {
    return {
    type: 'SUCCESS',
    message: msg
    }
    }

    // 异步请求失败需要用到的同步 action 创建函数
    function actionError() {
    return {
    type: 'ERROR'
    }
    }

    // 暴露异步 Action
    export function asyncAction(param) {
    // 异步 action 的固定写法,返回一个函数,第一个参数为 dispatch 函数,第二个参数为 state
    return (dispatch, state) => {
    // 执行异步操作
    fetch(url)
    .then(reponse => response.json)
    // 请求成功调用成功的同步 Action
    .then(json => dispatch(actionSuccess(actionSuccess)))
    .catch(error => dispatch(actionError()))
    }
    }
  • 在组件中调用

    • 在组件中和调用同步 Action 一致
      1
      store.dispatch(asyncAction(param));
  • 在 Reducer 中不需要处理异步 Action,还是只关注同步 Action 即可。因为异步 Action 结束之后还是会调用同步 Action 发送数据更新指令


实现原理

本文只是单纯的记录一下 redux-thunk 中间件如何进行使用,想要深入了解 applyMiddleware 和 redux-thunk 实现原理的朋友可以移步至阮老师的

Redux 入门教程(二):中间件与异步操作


applyMiddleware 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
function applyMiddleware() {
for (var _len = arguments.length, middlewares = new Array(_len), _key = 0; _key < _len; _key++) {
middlewares[_key] = arguments[_key];
}

return function (createStore) {
return function () {
var store = createStore.apply(void 0, arguments);

var _dispatch = function dispatch() {
throw new Error("Dispatching while constructing your middleware is not allowed. " + "Other middleware would not be applied to this dispatch.");
};

var middlewareAPI = {
getState: store.getState,
dispatch: function dispatch() {
return _dispatch.apply(void 0, arguments);
}
};
var chain = middlewares.map(function (middleware) {
return middleware(middlewareAPI);
});
_dispatch = compose.apply(void 0, chain)(store.dispatch);
return _objectSpread({}, store, {
dispatch: _dispatch
});
};
};
}

redux-thunk 源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => next => action => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}

return next(action);
};
}

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

export default thunk;