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).
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:
- Arrow functions and
- Function#bind().
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.