Отменить предыдущий запрос на выборку с помощью redux-thunk - PullRequest
1 голос
/ 20 февраля 2020

Предыстория проблемы:

Я создаю приложение React / Redux, которое использует redux-thunk и wretch (обертку выборки) для обработки асинхронных запросов.

У меня есть несколько поисковых действий, которые могут значительно различаться по времени загрузки, вызывая нежелательное поведение.

Я рассмотрел использование AbortController (), но он либо отменяет все мои запросы напрямую, либо не отменяет предыдущий запрос.

пример задачи:

  • Запросить поиск "JOHN", затем запросить поиск "JOHNSON".
  • Сначала возвращаются результаты для "JOHNSON", и затем результаты для «JOHN» возвращаются позже и перезаписывают результаты «JOHNSON».

Цель:

Инициирование запроса должно прервать предыдущие ожидающие запросы.

пример желаемого поведения:

  • Запросить поиск "JOHN", затем запросить поиск "JOHNSON".
  • При инициировании запроса для "JOHNSON" отложенный запрос для "JOHN" прерывается.

Код:

actions. js

Действие fetchData вызывается с помощью onClick или других функций.

import api from '../../utils/request';
export function fetchData(params) {
  return dispatch => {
    dispatch(requestData());
    return api
      .query(params)
      .url('api/data')
      .get()
      .fetchError(err => {
        console.log(err);
        dispatch(apiFail(err.toString()));
      })
      .json(response => dispatch(receiveData(response.items, response.totalItems)))
  }
}

export function requestData() {
  return {
    type: REQUEST_DATA,
    waiting: true,
  }
}

export function receiveData(items, totalItems) {
  return {
    type: RECEIVE_DATA,
    result: items,
    totalItems: totalItems,
    waiting: false,
  }
}

export function apiFail(err) {
  return {
    type: API_FAIL,
    error: err,
    waiting: false,
  }
}

utils / request. js

Это импорт негодяев. Wretch - это обертка выборки, поэтому она должна работать аналогично извлечению.

import wretch from 'wretch';

/**
 * Handles Server Error
 * 
 * @param {object}      err HTTP Error
 * 
 * @return {undefined}  Returns undefined
 */
function handleServerError(err) {
  console.error(err);
}

const api = wretch()
  .options({ credentials: 'include', mode: 'cors' })
  .url(window.appBaseUrl || process.env.REACT_APP_API_HOST_NAME)
  .resolve(_ => _.error(handleServerError))

export default api;

Попытка:

Я пытался использовать параметр .signal () wretch с AbortController (), вызывая .abort () после запроса, но это отменяет все запросы, вызывая разрыв приложения. Пример ниже:

import wretch from 'wretch';

/**
 * Handles Server Error
 * 
 * @param {object}      err HTTP Error
 * 
 * @return {undefined}  Returns undefined
 */
function handleServerError(err) {
  console.error(err);
}
const controller = new AbortController();

const api = wretch()
  .signal(controller)
  .options({ credentials: 'include', mode: 'cors' })
  .url(window.appBaseUrl || process.env.REACT_APP_API_HOST_NAME)
  .resolve(_ => _.error(handleServerError))

controller.abort();
export default api;

Я пытался переместить логи c в разные места, но кажется, что все действия отменяются или не выполняются ни одно из них.

Любой совет относительно того, как на go по этому поводу был бы признателен, это очень важно для моей команды.

Спасибо

1 Ответ

1 голос
/ 21 февраля 2020

Я чувствую себя довольно глупо сейчас, но это то, что нужно, чтобы заставить его работать.

Шаги решения:

  • Установите AbortController на initialState редуктора

редуктор. js

export default (state = {
  controller: new AbortController(),
}, action) => {
  switch (action.type) {
    ...
  • Получить AbortController из состояния в начале действия выборки и прервите его.
  • Создайте новый AbortController и передайте его в действие requestData.
  • Передайте новый AbortController в параметр signal() вызова wretch.

действий. js

export function fetchData(params) {
  return (dispatch, getState) => {
    const { controller } = getState().reducer;
    controller.abort();

    const newController = new AbortController();
    dispatch(requestData(newController));
    return api
      .signal(newController)
      .query(params)
      .url('api/data')
      .get()
      .fetchError(err => {
        console.log(err);
        dispatch(apiFail(err.toString()));
      })
      .json(response => dispatch(receiveData(response.items, response.totalItems)))
  }
}

export function requestData(controller) {
  return {
    type: REQUEST_DATA,
    waiting: true,
    controller,
  }
}

В редукторе, для случая действия requestData, установите новый AbortController в состояние.

reducer. js

case REQUEST_DATA:
  return {
    ...state,
    waiting: action.waiting,
    controller: action.controller
  };

Есть некоторые дополнительные функции с параметром wretch, .onAbort(), которые позволяют вам отправлять другие действия при отмене запроса. Я еще не закодировал это, но я решил включить информацию для всех, кто борется с этим.

...