简体   繁体   English

在redux-saga中重试功能

[英]retry functionality in redux-saga

in my application I have the following code 在我的应用程序中,我有以下代码

componentWillUpdate(nextProps) {
  if(nextProps.posts.request.status === 'failed') {
    let timer = null;

    timer = setTimeout(() => {
      if(this.props.posts.request.timeOut == 1) {
        clearTimeout(timer);
        this.props.fetchData({
          page: this.props.posts.request.page
        });
      } else {
        this.props.decreaseTimeOut();
      }
    }, 1000);
  }
}

What it does is that, when an API request encountered an error maybe because there is no internet connection (like how facebook's chat works), or there was an error in the back-end, it would retry after five seconds, but the setTimeout needs to be set every one second to update a part of the store, ie, the line this.props.decreaseTimeOut(); 它的作用是,当API请求遇到错误时可能是因为没有互联网连接(比如facebook的聊天工作方式),或者后端有错误,它会在5秒后重试,但是setTimeout需要每隔一秒设置一次以更新商店的一部分,即行this.props.decreaseTimeOut(); , but if the counter has run out, so five seconds have passed, the if block would run and re-dispatch the fetchData action . ,但是如果计数器已经用完,那么五秒钟就会过去, if block会运行并重新调度fetchData action

It works well and I have no problem with it, at least in terms of functionality, but in terms of code design, I know that it's a side-effect and it should not be handled in my react-component, and since I'm using redux-saga (but I'm new to redux-saga, I just learned it today), I want to transform that functionality into a saga, I don't quite have an idea as to how to do that yet, and here is my fetchData saga by the way. 它运行良好,我没有问题,至少在功能方面,但在代码设计方面,我知道这是一个side-effect ,它不应该在我的react-component中处理,因为我是使用redux-saga(但我是redux-saga的新手,我今天刚刚学会了它),我想把这个功能变成一个传奇,我还不知道如何做到这一点,而且这里fetchData saga ,这是我的fetchData saga

import {
  take,
  call,
  put
} from 'redux-saga/effects';

import axios from 'axios';

export default function* fetchData() {
  while(true) {
    try {
      let action = yield take('FETCH_DATA_START');
      let response = yield call(axios.get, '/posts/' + action.payload.page);
      yield put({ type: 'FETCH_DATA_SUCCESS', items: [...response.data.items] });
    } catch(err) {
      yield put({ type: 'FETCH_DATA_FAILED', timeOut: 5 });
    }
  }
}

The less intrusive thing for your code is using the delay promise from redux-saga: 对代码的侵扰性较小的是使用redux-saga的延迟保证:

catch(err) {
   yield put({ type: 'FETCH_DATA_FAILED'});

   for (let i = 0; i < 5; i++) {
       yield call(delay, 1000);
       yield put(/*Action for the timeout/*);
  }
}

But I'd refactor your code in this way: 但我会以这种方式重构你的代码:

function* fetchData(action) {
    try {
      let response = yield call(axios.get, '/posts/' + action.payload.page);
      yield put({ type: 'FETCH_DATA_SUCCESS', items:[...response.data.items] });
    } catch(err) {
      yield put({ type: 'FETCH_DATA_FAILED'});
      yield put({ type: 'SET_TIMEOUT_SAGA', time: 5 });
    }
  }
}

function *setTimeoutsaga(action) {
   yield put({type: 'SET_STATE_TIMEOUT', time: action.time}); // Action that update your state
   yield call(delay, 1000);

   // Here you use a selector which take the value if is disconnected:
   // https://redux-saga.js.org/docs/api/#selectselector-args
   const isStillDisconnected = select() 
   if (isStillDisconnected) {
       yield put({type: 'SET_TIMEOUT_SAGA', time: action.time - 1});
}

function *fetchDataWatchers() {
    yield takeEvery('FETCH_DATA_START', fetchData);
    yield takeEvery('SET_TIMEOUT_SAGA', setTimeoutSaga);

    // You can insert here as many watcher you want
}

export default [fetchDataWatchers]; // You will use run saga for registering this collection of watchers

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM