一、Redux的Middlewares
① 当一个action被dispatch之前,会经过Middleware。
② 这个Middleware的作用是去截获某种特殊的类型的action,比方说Ajax请求这种类型的action,会有一个redux-thunk这样一个中间件去处理。当Middleware接收到这个action的时候,不是直接把他丢给dispatch给reducer,而是去访问一个API,当API的返回结果为true,则dispatch一个成功的action,如果为false,就dispatch一个失败的action。
③ 所以说一个Ajax请求被中间件截获之后,会先做一个预处理,预处理完成之后,他才会真正的把action给dispatch出去来更新store,这样才算完成一个Ajax请求的过程。
④ 常用的Middleware有redux-thunk和redux-saga
二、Middleware工作流程
① 截获action
Middleware可以截获某种特殊类型的action。对于Ajax请求这种类型的action,会由redux-thunk这样一个中间件去截获,他判断是否要截获的一个action的机制是判断这个action是不是一个promise,是不是一个函数。如果是一个函数就会执行它,因为这个函数内部会真正的去发一个Ajax请求。
② 发出action
处理完成之后就发出结果action
三、异步action
import axios from 'axios';
import {
EXAMPLES_FETCH_REDDIT_LIST_BEGIN,
EXAMPLES_FETCH_REDDIT_LIST_SUCCESS,
EXAMPLES_FETCH_REDDIT_LIST_FAILURE,
EXAMPLES_FETCH_REDDIT_LIST_DISMISS_ERROR,
} from './constants';
// Rekit uses redux-thunk for async actions by default: https://github.com/gaearon/redux-thunk
// If you prefer redux-saga, you can use rekit-plugin-redux-saga: https://github.com/supnate/rekit-plugin-redux-saga
//异步action
//这个是个特殊的action,返回值是一个函数。函数里面包含了几个action,这样中间件看到函数就把他给截获,等待他的promise返回
export function fetchRedditList(args = {}) {
return dispatch => {
// optionally you can have getState as the second argument
dispatch({
type: EXAMPLES_FETCH_REDDIT_LIST_BEGIN,
});
// Return a promise so that you could control UI flow without states in the store.
// For example: after submit a form, you need to redirect the page to another when succeeds or show some errors message if fails.
// It's hard to use state to manage it, but returning a promise allows you to easily achieve it.
// e.g.: handleSubmit() { this.props.actions.submitForm(data).then(()=> {}).catch(() => {}); }
const promise = new Promise((resolve, reject) => {
// doRequest is a placeholder Promise. You should replace it with your own logic.
// See the real-word example at: https://github.com/supnate/rekit/blob/master/src/features/home/redux/fetchRedditReactjsList.js
// args.error here is only for test coverage purpose.
const doRequest = axios.get('http://www.reddit.com/r/reactjs.json');
doRequest.then(
res => {
dispatch({
type: EXAMPLES_FETCH_REDDIT_LIST_SUCCESS,
data: res.data,
});
resolve(res);
},
// Use rejectHandler as the second argument so that render errors won't be caught.
err => {
dispatch({
type: EXAMPLES_FETCH_REDDIT_LIST_FAILURE,
data: { error: err },
});
reject(err);
}
);
});
return promise;
};
}
// Async action saves request error by default, this method is used to dismiss the error info.
// If you don't want errors to be saved in Redux store, just ignore this method.
//一个同步action
export function dismissFetchRedditListError() {
return {
type: EXAMPLES_FETCH_REDDIT_LIST_DISMISS_ERROR,
};
}
//reducer
export function reducer(state, action) {
switch (action.type) {
case EXAMPLES_FETCH_REDDIT_LIST_BEGIN:
// Just after a request is sent
return {
...state,
fetchRedditListPending: true,
fetchRedditListError: null,
};
case EXAMPLES_FETCH_REDDIT_LIST_SUCCESS:
// The request is success
return {
...state,
redditList: action.data.data.children,
fetchRedditListPending: false,
fetchRedditListError: null,
};
case EXAMPLES_FETCH_REDDIT_LIST_FAILURE:
// The request is failed
return {
...state,
fetchRedditListPending: false,
fetchRedditListError: action.data.error,
};
case EXAMPLES_FETCH_REDDIT_LIST_DISMISS_ERROR:
// Dismiss the request failure error
return {
...state,
fetchRedditListError: null,
};
default:
return state;
}
}
参考文档:https://redux.js.org/advanced/async-actions
参考视频:https://time.geekbang.org/course/detail/100009301-9453?utm_source=pinpaizhuanqu&utm_medium=geektime&utm_campaign=guanwang&utm_term=guanwang&utm_content=0511