Reputation: 16791
The Component.vue provided was part of a larger web app so I ripped out the relevant code for this question. What I didn't notice was a VERY tiny change I made in ripping out the code that had a very big impact.
There's a difference between:
mounted() {
// ....
}
and:
mounted: () => {
// ....
}
Upon careful investigation this morning I found this mistake in my code and I've updated the question to reflect the actual code that was failing.
I may just be tired, but before going to bed I wanted to ask for help here and see if someone can find my issue. I have a very simple Vue component that isn't working:
Component.vue:
<template>
<div>
<p v-for="item in items">{{ item.text }}</p>
</div>
</template>
<script>
export default {
data() {
return {
items: []
};
},
mounted: () => {
var _this = this;
$.ajax("/items.json").done(result => {
_this.items = result;
});
}
};
</script>
items.json
[
{"text": "ABC"},
{"text": "XYZ"}
]
The paragraphs are never rendering. Upon inspection it looks like _this.items
doesn't exist prior to setting it in the AJAX handler (I expect it to be an empty array) and _this.$data
also doesn't exist
~Is the value of this
different in the mounted method than elsewhere in Vue?~ Or did I make a simple mistake?
Writing the mounted
function in this way (with the colon) causes the value of this
to be different. Why is that?
Upvotes: 3
Views: 13595
Reputation: 16791
Upon further research, I have learned of the subtle difference between normal functions and arrow functions. I previously thought the latter was just a short-hand, but it also does not have its own context.
The method mounted: () => {}
utilizes an arrow function, and therefore
...does not have its own
this
,arguments
,super
, ornew.target
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
Here is a simple example demonstrating the difference which can be tested in the Chrome console
let testFunc = function() { console.log(this); }
testFunc(); // Window {...}
testFunc.bind("test")(); // String {"test"}
testFunc = () => { console.log(this); }
testFunc(); // Window {...}
testFunc.bind("test")(); // Window {...}
When utilizing an arrow function, it becomes impossible to bind a value to this
. This means that in the Vue internals they are unable to bind the Vue instance to this
.
The method mounted() { }
is only utilizing the ES6 short-hand for objects, and not an arrow function (therefore it does have its own context and you can bind the this
variable)
Upvotes: 8
Reputation: 2555
Mounting hooks are often the most-used hooks, for better or worse. They allow you to access your component immediately before and after the first render. They do not, however, run during server-side rendering.
Use if: You need to access or modify the DOM of your component immediately before or after the initial render.
Do not use if: You need to fetch some data for your component on initialization. Use created() (or created + activated for keep-alive components) for this instead, especially if you need that data during server-side rendering.
So try to change mounted() to created() and see if it works. Also, I suggest you look at axios to send request which is a better alternative to $.ajax(). Make sure you are requesting the json file from the right path.
Upvotes: 2