最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to save reference to "this" in Vue component? - Stack Overflow

programmeradmin3浏览0评论

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).

Share Improve this question edited Mar 22, 2018 at 1:32 supersan asked Mar 21, 2018 at 22:14 supersansupersan 6,1813 gold badges49 silver badges71 bronze badges 13
  • Why not do let self = this; just before the ajax() call? What you're experiencing is an issue with scoping. By placing the variable declaration within the scope of load(), 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 the data 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
 |  Show 8 more ments

1 Answer 1

Reset to default 4

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./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.

发布评论

评论列表(0)

  1. 暂无评论