RXJS:重试时调度操作



我编写了一个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));
        })
);

注意:(也来自文档(提供给史诗的商店是商店的轻量级版本,而不是完整的商店对象。提供的存储仅包含方法getStatedispatch

最新更新