React - запрашивает отмену при смене страницы - PullRequest
0 голосов
/ 02 октября 2018

Я использую axios для извлечения / публикации данных на моем сервере, и мой текущий подход выглядит следующим образом:

1.Запрос делается с использованием избыточных действий с redux-thunk, и действие выглядит так:

export const getRecords = () => (dispatch, getState, { api }) => {
  const type = GET_RECORDS_LOAD;
  return dispatch({
    type,
    promise: api.Records.get({ type }),
  });
};

2.api.Record.get выглядит следующим образом:

import _ from 'lodash';
import axios from 'axios';

const APIInstance = axios.create({
  baseURL: process.env.API_URL,
});

const getCancelToken = id => new axios.CancelToken((c) => {
  const cancel = c;
  const cancelationTokens = _.get(window, 'cancelationTokens', {});
  cancelationTokens[id] = cancel;
  _.set(window, 'cancelationTokens', cancelationTokens);
});

const api = {
  Records: {
    get: ({ type }) => APIInstance.get('/my-records', { cancelToken: getCancelToken(type) }),
  },
};

Здесь я создаю cancelToken на основе типа действия приставки и сохраняю его в объекте window.cancelationTokens, поэтому их можно отменить в любом месте изприложение.

3.Отмена на componentWillUnmount

import * as Types from './path/to/action/types';

const cancelToken = (type) => {
  const cancel = _.get(window, `cancelationTokens.${type}`);
  if (!cancel) return;
  cancel();
}

componentWillUnmount() {
  cancelToken(Types.GET_RECORDS_LOAD);
  // If more request I have to cancel them manually...
}

Как видите, нет серьезных проблем с этим подходом, но если я выполняю большое количество запросов на одной странице, я должен отменить их все вручную в componentWillUnmount.

Мои вопросы:

  1. Можно ли автоматически отменить текущий запрос, если пользователь изменит страницу в моем приложении?
  2. Если да - это правильный способ сделать это, или есть более простой способ отменить запросы?

1 Ответ

0 голосов
/ 02 октября 2018

Итак, я создал класс под названием RequestCancelation, который использует пакет history.Он может отменить запросы на основе переданного типа действия или на основе history.location.pathname.

RequestCancelation.js

import _ from 'lodash';
import axios from 'axios';
import createHistory from 'history/createBrowserHistory';

// In my case the history is imported from another file, as I pass
// it to the `Router` from `react-router-dom`. For the purpose of this
// example I created the history here.
const history = createHistory();

class RequestCancelation {
  static constants = {
    cancelationTokens: 'CANCELATION_TOKENS',
  }

  getTokens() {
    return _.get(window, RequestCancelation.constants.cancelationTokens, {});
  }

  setTokens(tokens) {
    return _.set(window, RequestCancelation.constants.cancelationTokens, tokens);
  }

  deleteTokens(key) {
    if (!key) return undefined;
    delete window[RequestCancelation.constants.cancelationTokens][key];
    return this.getTokens();
  }

  getLocationKey() {
    return _.get(history, 'location.pathname');
  }

  getCancelToken(type) {
    return new axios.CancelToken((c) => {
      const cancel = c;
      if (typeof window === 'undefined') return;
      const tokens = this.getTokens();
      if (type) {
        tokens[type] = cancel;
      } else {
        const key = this.getLocationKey();
        if (!key) return;
        if (!tokens[key]) tokens[key] = [];
        tokens[key].push(cancel);
      }
      this.setTokens(tokens);
    });
  }

  cancelRequest(type) {
    if (!type) {
      return console.warn('#cancelRequest - please specify \'type\'');
    }
    if (typeof window === 'undefined') return undefined;
    const tokens = this.getTokens();
    const cancel = tokens[type];
    if (!cancel) return undefined;
    cancel();
    return this.deleteTokens(type);
  }

  cancelRequests() {
    if (typeof window === 'undefined') return undefined;
    const tokens = this.getTokens();
    const key = this.getLocationKey();
    if (!key) return undefined;
    const cancels = tokens[key];
    if (!cancels) return undefined;
    cancels.forEach(cancel => cancel());
    return this.deleteTokens(key);
  }

  clearTokens() {
    if (typeof window === 'undefined') return undefined;
    window[RequestCancelation.constants.cancelationTokens] = {};
    return this.getTokens();
  }
}

const cancelation = new RequestCancelation();

export default cancelation;

Надеюсь, это кому-нибудь поможет и, возможно,кто-то может улучшить его:)

Также доступно как gist .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...