我编写了一个react,redux,rxjs应用程序,它每5秒从API获取一次数据。每次应用程序获取时,我都会显示一个加载指示器。
如果调用失败,它将从retryWhen
机制开始,然后我需要将存储从loading
更新到retrying
以便我可以更新视图。
目前我被困住了,因为我不知道如何从retryWhen
更新商店。
应用组件
import React, { Component } from 'react';
import PropTypes from 'prop-types';
class App extends Component {
state = {};
componentWillMount() {
this.fetchAdvertisement();
}
fetchAdvertisement = () => {
console.log('Start advertisement call');
console.log('---------------------------------------------');
const { displayId, unitId } = this.props.match.params;
this.props.fetchAdvertisement(displayId, unitId);
};
render() {
return <div>Hello world</div>;
}
}
App.propTypes = {
fetchAdvertisement: PropTypes.func.isRequired,
match: PropTypes.shape({
params: PropTypes.shape({
displayId: PropTypes.string.isRequired,
unitId: PropTypes.string.isRequired,
}).isRequired,
}).isRequired,
};
export default App;
动作创作者
import * as ACTION_TYPES from 'modules/contants';
export function fetchAdvertisement(displayId, unitId) {
return { type: ACTION_TYPES.ADVERTISEMENT_FETCH, payload: { displayId, unitId } };
}
export function fetchAdvertisementSuccess(payload) {
return { type: ACTION_TYPES.ADVERTISEMENT_FETCH_SUCCESS, payload };
}
export function fetchAdvertisementRetrying() {
return { type: ACTION_TYPES.ADVERTISEMENT_FETCH_RETRYING };
}
export function fetchAdvertisementFailed(payload) {
return { type: ACTION_TYPES.ADVERTISEMENT_FETCH_FAILED, payload };
}
史诗
export const retryMechanism = ({
scalingDuration = 1000,
excludedStatusCodes = []
} = {}) => attempts =>
attempts.pipe(
mergeMap((error, i) => {
// Update the store by dispatching the action creator fetchAdvertisementRetrying
const retryAttempt = i + 1;
if (excludedStatusCodes.find(e => e === error.status)) {
return _throw(error);
}
console.log(`Attempt ${retryAttempt}: retrying in ${scalingDuration * retryAttempt}s`);
return timer(scalingDuration * retryAttempt);
})
);
export const fetchAdEpic = action$ =>
action$.ofType(ACTION_TYPES.ADVERTISEMENT_FETCH).mergeMap(action =>
ajax
.getJSON(`${process.env.REACT_APP_API_URL}/request-ad/${action.payload.displayId}`)
.map(response => {
if (response.data) {
return fetchAdvertisementSuccess(response.data);
}
})
.retryWhen(retryMechanism())
.catch(error => {
console.log(error);
return Observable.of(fetchAdvertisementFailed(error.data));
})
);
还原剂
import * as ACTION_TYPES from 'modules/contants';
const initialState = {};
export default (state = initialState, action) => {
switch (action.type) {
case ACTION_TYPES.ADVERTISEMENT_FETCH: {
console.log('Loading');
console.log('---------------------------------------------');
return state;
}
case ACTION_TYPES.ADVERTISEMENT_FETCH_RETRYING: {
console.log('Retrying');
console.log('---------------------------------------------');
return state;
}
case ACTION_TYPES.ADVERTISEMENT_FETCH_SUCCESS: {
console.log('success');
console.log('---------------------------------------------');
return state;
}
case ACTION_TYPES.ADVERTISEMENT_FETCH_FAILED: {
console.log('error');
console.log('---------------------------------------------');
return state;
}
default: {
return state;
}
}
};
我不知道 rxjs 是如何工作的,所以很多代码对我来说看起来很陌生。快速浏览此处的 rxjs 中间件 Epic 文档表明,中间件将两个参数传递给您的长篇故事:action$
和 store
。因此,您可以按如下方式重写代码:
export const retryMechanism = (dispatch) => ({ scalingDuration = 1000, excludedStatusCodes = [] } = {}) => attempts =>
attempts.pipe(mergeMap((error, i) => {
// Let the store know i am retry-ing by calling the function fetchAdvertisementRetrying
dispatch(fetchAdvertisementRetrying());
const retryAttempt = i + 1;
if (excludedStatusCodes.find(e => e === error.status)) {
return _throw(error);
}
console.log(`Attempt ${retryAttempt}: retrying in ${scalingDuration * retryAttempt}s`);
return timer(scalingDuration * retryAttempt);
})
);
export const fetchAdEpic = (action$, store) =>
action$.ofType(ACTION_TYPES.ADVERTISEMENT_FETCH).mergeMap(action =>
ajax
.getJSON(`${process.env.REACT_APP_API_URL}/request-ad/${action.payload.displayId}`)
.map(response => {
if (!response.data) {
return fetchAdvertisementSuccess(response.data);
}
})
.retryWhen(retryMechanism(store.dispatch)())
.catch(error => {
console.log(error);
return Observable.of(fetchAdvertisementFailed(error.data));
})
);
注意:(也来自文档(提供给史诗的商店是商店的轻量级版本,而不是完整的商店对象。提供的存储仅包含方法getState
和dispatch
。