redux-thunk:处理异步action

下面代码点击按钮后,直接修改了按钮的文本,这个文本是个固定的值。

1
2
3
4
5
6
7
8
9
// action.js
export const CHANGE_BTN_TEXT = 'CHANGE_BTN_TEXT';

export const changeBtnText = (text) => {
return {
type: T.CHANGE_BTN_TEXT,
payload: text
};
};

但是在我们实际生产的过程中,很多情况都是需要去请求服务端拿到数据再修改的,这个过程是一个异步的过程。又或者需要setTimeout去做一些事情。

1
2
3
4
5
6
7
8
9
10
11
12
const mapDispatchToProps = (dispatch) => {
return {
changeText: (text) => {
dispatch(changeBtnText('正在加载中'));
axios.get('http://test.com').then(() => {
dispatch(changeBtnText('加载完毕'));
}).catch(() => {
dispatch(changeBtnText('加载有误'));
});
}
};
};
  • 问题来了,当请求后台的过程非常快,导致加载完毕先出现,然后再展示加载中。
  • 这个时候我们需要去通过store.getState获取当前状态,从而判断到底是展示正在加载中还是展示加载完毕
  • 这个过程就不能放在mapDispatchToProps中了,而需要放在中间件中,因为中间件中可以拿到store。
1
2
3
4
5
6
7
8
9
// 首先创造store的时候需要应用react-thunk
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducers';

const store = createStore(
reducer,
applyMiddleware(thunk)
);
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
30
31
32
import axios from 'axios';
import * as T from './actionTypes';

export const changeBtnText = (text) => {
return {
type: T.CHANGE_BTN_TEXT,
payload: text
};
};

export const changeBtnTextAsync = (text) => {
return (dispatch, getState) => {
if (!getState().isLoading) {
dispatch(changeBtnText('正在加载中'));
}
axios.get(`http://test.com/${text}`).then(() => {
if (getState().isLoading) {
dispatch(changeBtnText('加载完毕'));
}
}).catch(() => {
dispatch(changeBtnText('加载有误'));
});
};
};

const mapDispatchToProps = (dispatch) => {
return {
changeText: (text) => {
dispatch(changeBtnTextAsync(text));
}
};
};

thunk的源码超级简单:

1
2
3
4
5
6
7
8
9
10
11
12
13
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;

createThunkMiddleware加强了dispatch的功能,在dispatch一个action之前,去判断action是否是一个函数,如果是函数,那么就执行这个函数。

通过redux-thunk我们可以简单地进行异步操作,并且可以获取到各个异步操作时期状态的值。