функция повтора в redux-saga

в моем приложении у меня есть следующий код

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);
  }
}

Что он делает, так это то, что, когда запрос API обнаружил ошибку, возможно, из-за отсутствия подключения к Интернету (например, как работает чат facebook) или произошла ошибка в серверной части, он повторит попытку через пять секунд, но setTimeout требуется устанавливается каждую секунду для обновления части хранилища, то есть строки this.props.decreaseTimeOut();, но если счетчик закончился, то есть прошло пять секунд, if block запустится и повторно отправит fetchData action.

Он работает хорошо, и у меня нет проблем с ним, по крайней мере, с точки зрения функциональности, но с точки зрения дизайна кода я знаю, что это side-effect, и его не следует обрабатывать в моем реактивном компоненте, и поскольку я использую redux -saga (но я новичок в redux-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 });
    }
  }
}

person aprilmintacpineda    schedule 08.05.2017    source источник


Ответы (1)


Менее навязчивым для вашего кода является использование обещания delay от редукс-сага:

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/*);
  }
}

Но я бы реорганизовал ваш код следующим образом:

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
person rpadovani    schedule 08.05.2017
comment
Это выглядит потрясающе, но я не хочу использовать takeEvery для своего FETCH_DATA_START, потому что это позволило бы пользователям просто нажимать fetch data button снова и снова, отправляя несколько запросов, а я этого не хочу, я хочу отправлять только один запрос время, так что я использовал дубль, это плохо? - person aprilmintacpineda; 09.05.2017
comment
@ four-eyes-04-04, тогда вы можете использовать takeLatest, который делает именно то, что вам нужно :) Но в любом случае, ваш код в порядке, мне просто не нравится структура while true, но если вы предпочитаете это, просто используйте delay, как я предложено в первом фрагменте - person rpadovani; 09.05.2017
comment
Спасибо за ваше предложение, мне удалось успешно реализовать эту функцию. :-) - person aprilmintacpineda; 10.05.2017
comment
@ four-eyes-04-04, пожалуйста, примите мой ответ stackoverflow.com/help/someone-answers или опубликуйте свое решение , если это другое - person rpadovani; 10.05.2017