Запретить обновление на отключенном контроллере - PullRequest
1 голос
/ 06 мая 2020

У меня есть приложение для реагирования, которое запрашивает данные из API при загрузке определенных страниц. Если пользователь переключает страницы до загрузки данных, я бы хотел прервать его / предотвратить любые обновления на этом отключенном контроллере. Я прочитал несколько руководств, и похоже, что это должно работать, но продолжает давать мне ту же ошибку. Возможно, я реализовал это неправильно, может ли кто-нибудь дать мне совет?

модуль запроса

import axios from 'axios';

import {config} from '../common/config';

const supportedMethods = ["GET","POST","PATCH","PUT","DELETE"];

var subscriptions = {};
export const request = async (name, endpoint, method, data, callback) => {

  var endpointPass = config.apiBaseUrl+endpoint;
  var localApiEndPoint = true;
  if(endpoint.includes("http")){
    endpointPass = endpoint;
    localApiEndPoint = false;
  }

  const csrf = localStorage.getItem("csrf");

  if(!supportedMethods.includes(method)){
    console.error("Ajax Request Error: Unrecognized Method: ",method);
    return false;
  }

  const source = axios.CancelToken.source();

  if(name in subscriptions){
    unSubRequest(name);
  }

  subscriptions[name] = {
    source: source,
  };

  var axiosData = {
    cancelToken: source.token,
    async: true,
    method: method,
    timeout: 35000,
    headers: {},
    url: endpointPass,
  };

  const headers = {
    'Content-Type': 'application/json',
  };

  if(localApiEndPoint){
    headers.csrf = csrf;
    if(localStorage.getItem("user")){
      let user = JSON.parse(localStorage.getItem("user"));
      headers['auth-id'] = user.auth.id;
      headers['auth-token'] = user.auth.token;
    }
  }    

  if(method !== "GET"){
    axiosData.data = data
  } 

  axiosData.headers = headers;

  axios(axiosData)
    .then(function(response){
      if(response.data === undefined){
        console.log("Error, response data null but came back 200",response);
        callback.catch({code: 1, message:"Server Error: Then Response.data null"});
      }else{
        callback.then(response);
      }
    })
    .catch(function(error){
      console.log("Server Error catch response: ",error.response);
      let err = {code: 1, message: "Server Error - see console for more details"};
      if(error !== undefined && error.response !== undefined && 
        error.response.data !== undefined && error.response.data.err !== undefined){
        err = error.response.data.err;
      }
      callback.catch(err);
    }
  ).finally(function(){
    callback.finally();
    unSubRequest(name);
  });

}

export const unSubRequest = (name) => {
  if(name in subscriptions){
    if(subscriptions[name].source !== undefined){
      let source = subscriptions[name].source;
      source.cancel();
    }
    delete subscriptions[name];
  }
}

пример использования

useEffect(() => {
  doStuff();
  return () => {
    unSubRequest("do-stuff");
  }
},[])

const doStuff = () => {
  setLoading(true);
  request("do-stuff","do-stuff","GET", {}, {
    then: function(res){ 
      setDoStuffVariable(res.data.doStuff);
    },
    catch: function(err){ 
      setErrorMessage(err.message);
    },
    finally: function(){ 
      setLoading(false);
    }
  });
}

Изменить: вот ошибка, которую я получить

1.chunk.js:68737 Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
    in Documents (at app.js:64)
    in component (at private-route.js:22)

1 Ответ

2 голосов
/ 06 мая 2020

Внесите следующие изменения в свой код.

  • Когда вы отменяете запрос ax ios, выполняется блок catch. В вашем блоке catch вы устанавливаете состояние setErrorMessage(err.message). Следовательно, вы получаете сообщение об ошибке / предупреждение. Не обновлять состояние для отмен. Сделайте необходимые проверки axios.isCancel(error) и обновите ТОЛЬКО ваше реальное состояние ошибки.
  • Не обновляйте свое состояние в блоке finally.

См. Ниже пример изменений кода.

axios(axiosData)
    .then(function(response) {
      if (response.data === undefined) {
        console.log("Error, response data null but came back 200", response);
        callback.catch({
          code: 1,
          message: "Server Error: Then Response.data null"
        });
      } else {
        callback.then(response);
      }
    })
    .catch(function(error) {
      console.log("Server Error catch response: ", error);
      if (axios.isCancel(error)) { // <------ check if request is cancelled
        console.log("Previous request canceled  - i should not update state here", error);
      } else {
        let err = {
          code: 1,
          message: "Server Error - see console for more details"
        };
        if (
          error !== undefined &&
          error.response !== undefined &&
          error.response.data !== undefined &&
          error.response.data.err !== undefined
        ) {
          err = error.response.data.err;
        }
        callback.catch(err);
      }
    })
    .finally(function() {
      // callback.finally(); <------ don't update state in finally
      unSubRequest(name);
    });
...