0

I want to use the Axios interceptors to show my loader component while Axios is performing a request. In my root component I put those interceptors in the created() function. In this component I also have a property called isLoading which is set to false. When a request is made I want to set it to true. But when I try to access the property it says:

TypeError: Cannot read property isLoading of undefined

Why am I not able to access the isLoading property from inside the Axios function? This is my component:

<template>
  <v-app>
    <AppBar />
    <router-view/>
    <Loader v-if="isLoading"></Loader>
  </v-app>
</template>

<script>
import AppBar from '../components/AppBar';
import Loader from '../components/Loader';
import axios from 'axios';

export default {
  name: "App",
  components: {
    AppBar,
    Loader
  },
  data() {
    return {
      isLoading: false
    }
  },
  created() {
    axios.interceptors.request.use(function (config) {

      this.isLoading = true;

        return config;
      }, function (error) {
        this.isLoading = false;
        return Promise.reject(error);
      });

    axios.interceptors.response.use(function (response) {
        this.isLoading = false;

        return response;
      }, function (error) {
        return Promise.reject(error);
      });
  }
};
</script>
Baspa
  • 796
  • 6
  • 33

2 Answers2

2

Your closures are using their own this context, which is NOT the context you want. Replace them with arrow functions like this in order to access the this context of the enclosing scope (that is, your component state):

axios.interceptors.request.use((config) => {
    this.isLoading = true;
    return config;
}, (error) => {
    this.isLoading = false;
    return Promise.reject(error);
});
Ayrton
  • 2,020
  • 1
  • 9
  • 21
1

The word this always refers to the immediate scope. When using it inside a function from axios object it loses reference to your component. The solution is to simply capture that reference in a new variable

  created() {
    var vm = this;
    axios.interceptors.request.use(function (config) {

      vm.isLoading = true;

        return config;
      }, function (error) {
        vm.isLoading = false;
        return Promise.reject(error);
      });

    axios.interceptors.response.use(function (response) {
        vm.isLoading = false;

        return response;
      }, function (error) {
        return Promise.reject(error);
      });
  }

As this is treated very differently in arrow and normal functions, refer to When should I use Arrow functions in ECMAScript 6? for better understanding.

Varun Agarwal
  • 1,506
  • 11
  • 26
  • Is it better to use an arrow function or use your solution? – Baspa Oct 29 '19 at 14:24
  • If arrow functions work, go right a head, but when you start calling more functions with their own context, you need to do `var vm = this` and store the reference out. So just keep this in mind for a later date. – Varun Agarwal Oct 29 '19 at 17:32