我个人比较喜欢使用自定义中间件做到这一点。它使行动更容易遵循,并且具有更少的样板IMO。
我已经设置了我的中间件来查找匹配特定签名的操作返回的对象。如果找到这个对象模式,它会专门处理它。
例如,我使用看起来像这样的动作:
export function fetchData() {
return {
types: [ FETCH_DATA, FETCH_DATA_SUCCESS, FETCH_DATA_FAILURE ],
promise: api => api('foo/bar')
}
}
我定制的中间件看到该对象有一个types
阵列和promise
功能以及专门处理它。这里是什么样子:
import 'whatwg-fetch';
function isRequest({ promise }) {
return promise && typeof promise === 'function';
}
function checkStatus(response) {
if (response.status >= 200 && response.status < 300) {
return response;
} else {
const error = new Error(response.statusText || response.status);
error.response = response.json();
throw error;
}
}
function parseJSON(response) {
return response.json();
}
function makeRequest(urlBase, { promise, types, ...rest }, next) {
const [ REQUEST, SUCCESS, FAILURE ] = types;
// Dispatch your request action so UI can showing loading indicator
next({ ...rest, type: REQUEST });
const api = (url, params = {}) => {
// fetch by default doesn't include the same-origin header. Add this by default.
params.credentials = 'same-origin';
params.method = params.method || 'get';
params.headers = params.headers || {};
params.headers['Content-Type'] = 'application/json';
params.headers['Access-Control-Allow-Origin'] = '*';
return fetch(urlBase + url, params)
.then(checkStatus)
.then(parseJSON)
.then(data => {
// Dispatch your success action
next({ ...rest, payload: data, type: SUCCESS });
})
.catch(error => {
// Dispatch your failure action
next({ ...rest, error, type: FAILURE });
});
};
// Because I'm using promise as a function, I create my own simple wrapper
// around whatwg-fetch. Note in the action example above, I supply the url
// and optionally the params and feed them directly into fetch.
// The other benefit for this approach is that in my action above, I can do
// var result = action.promise(api => api('foo/bar'))
// result.then(() => { /* something happened */ })
// This allows me to be notified in my action when a result comes back.
return promise(api);
}
// When setting up my apiMiddleware, I pass a base url for the service I am
// using. Then my actions can just pass the route and I append it to the path
export default function apiMiddleware(urlBase) {
return function() {
return next => action => isRequest(action) ? makeRequest(urlBase, action, next) : next(action);
};
}
我个人很喜欢这种方法,因为它集中了大量的逻辑,让您的API操作是如何构成的标准执行。缺点是对那些不熟悉redux的人来说可能有点神奇。我也使用thunk中间件,这两者一起解决我迄今为止的所有需求。
我在我的应用程序中使用了类似的方法。如果您希望中央地点派发响应API相关事件的操作,这也是一种很好的方法。例如。显示/隐藏加载程序,在401响应的情况下将用户路由到登录屏幕。如果没有这些,那么在您调用API调用的任何地方都会散布这样的操作。来自Angular,这有助于我实现拦截器完成的功能。 – akaashanky
如果我想用中间件使用redux-thunk ..我可以在@ nross83上执行它吗?我需要派遣一个API调用和成功几次派发 –
@HarkiratSaluja是的,只需添加thunk中间件(以及您的定制中间件),它就可以工作。您可以使用Redux的applyMiddleware功能并传入您想要使用的所有中间件。我在我自己的项目中使用了thunk以及自定义中间件。 http://redux.js.org/docs/api/applyMiddleware.html – nross83