I'm not sure if I'm doing this properly. Please have a look at this simple Vue ponent 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 ponent 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 ponent 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 ponent 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).
I'm not sure if I'm doing this properly. Please have a look at this simple Vue ponent 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 ponent 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 ponent 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 ponent 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).
-
Why not do
let self = this;
just before theajax()
call? What you're experiencing is an issue with scoping. By placing the variable declaration within the scope ofload()
, you avoid overwriting the value with additional assignment operations. – B. Fleming Commented Mar 21, 2018 at 22:32 - 1 You can simple use this.name. I thought arrow functions are meant for that purpose. It takes the scope of the containing block – karthick Commented Mar 21, 2018 at 22:36
-
@karthick, indeed
this
should work where self is used in the example. – Richard Matsen Commented Mar 21, 2018 at 22:42 -
1
The reason why
let self
is getting over-written is that it's created globally. If you wish it to be per-instance, move it to thedata
property of the ponent. – Richard Matsen Commented Mar 21, 2018 at 22:45 -
1
@Bert so am I correct in thinking that you're saying that I said that an arrow function used here was not a lambda? Because, I wrote that he is not using JUST ANY lambda, his lambda is an ARROW function, and an arrow function hasn't got its own
this
. I see how it might have gotten about the wrong way. – N.B. Commented Mar 22, 2018 at 10:40
1 Answer
Reset to default 4What 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./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./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./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./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.