How to save reference to “this” in Vue component?

2019-08-09 05:37发布

I'm not sure if I'm doing this properly. Please have a look at this simple Vue component Test.vue:

<template>
    <div>
        Hi from {{name}}
    </div>
</template>

<script>
    let self;

    export default {
        created: function () {
            self = this;
        },
        methods: {
            load() {
                ajax().then((obj) => self.name = obj.data);
            }
        },
        data() {
            return {
                name: 'one',
            }
        }
    }
</script>

As you can see I'm saving the reference of this into a variable called self because the value of this changes in lambda functions, e.g. ajax().then((obj) => self.name = obj.data);

My problem is when this another instance of component is created, it overwrites the value of self in previous instance. So for example if I have two <test id="1"></test> and <test id="2"></test> then the later component overwrites the self variable of the first one (same happens in v-for too).

So my question is how can I create the self variable which saves to the value of this for every instance and doesn't get overwritten?

Edit: Yes I know I can do self = this inside every function but this is just a bare-bones example with 1 method. In my actual component I have 20+ functions I don't want to do self = this in every function. Which is why I can to create a variable that I can just assign once during the create call and use it everywhere (like we used to use that variable).

1条回答
Rolldiameter
2楼-- · 2019-08-09 05:57

What you are attempting to do is mostly unnecessary.

It is true that the value of this can be confusing at times in JavaScript. It is also true, though, that this is a well known problem, with well known solutions.

And these solutions, at least in problems related to the Vue instance, are:

But don't trust me just yet, let's go through an example. Take your source code:

    methods: {
        load() {
            ajax().then((obj) => self.name = obj.data);
        }
    },

As argument for the .then() you must pass a function. The value of this inside such function will depend on how you pass it.

In the first case (first solution from the two solutions above), one should use arrow functions (which you did). So, in that point of your code, the self is unnecessary because the this inside the arrow function still will point to the Vue instance.

    methods: {
        load() {
            console.log(this.name);
            ajax().then((obj) => this.name = obj.data);
        }
    },

In the example above, both this.name refer to the same property. See demo below.

const ajax = () => {
	return fetch('https://api.myjson.com/bins/18gqg9')
  	  .then((response) => response.json())
};

new Vue({
  el: '#app',
  data: {
		name: 'Alice'
  },
  methods: {
    yoo() {
      console.log('outside:', this.name);
      ajax().then((obj) => { this.name = obj.name; console.log('inside arrow, after change:', this.name); });
    }
  }
})
<script src="https://unpkg.com/vue@latest/dist/vue.min.js"></script>
<div id="app">
  <p>
    name: {{ name }}
  </p>
  <button @click="yoo">AJAX!</button>
  
  <p>Click the button above and check the console. The printed name variable is the same.</p>
</div>

Now, in the second solution, you would use a regular (non-arrow) function. But to make sure the this is kept, you would use .bind(this), as follows:

    methods: {
        load() {
            console.log(this.name);
            ajax().then(function (obj) { this.name = obj.data }.bind(this));
        }
    },

Similar to the previous case, in both places this.name refers to the same property. See demo below.

const ajax = () => {
	return fetch('https://api.myjson.com/bins/18gqg9')
  	  .then((response) => response.json())
};

new Vue({
  el: '#app',
  data: {
		name: 'Alice'
  },
  methods: {
    yoo() {
      console.log('outside:', this.name);
      ajax().then(function(obj) { this.name = obj.name; console.log('inside arrow, after change:', this.name); }.bind(this));
    }
  }
})
<script src="https://unpkg.com/vue@latest/dist/vue.min.js"></script>
<div id="app">
  <p>
    name: {{ name }}
  </p>
  <button @click="yoo">AJAX!</button>
  
  <p>Click the button above and check the console. The printed name variable is the same.</p>
</div>

So, as you can see, within the Vue instance, the declaration of such self variable is unnecessary.

查看更多
登录 后发表回答