3

Edit

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.

Question

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?

4
  • 1
    It should work, but since you're using an arrow function in the done, reassigning this isn't necessary. Try it without. Commented Jan 31, 2018 at 2:31
  • 1
    It works for me in a snippet where I use setTimeout instead of $.ajax. Commented Jan 31, 2018 at 2:38
  • 1
    Try switching $.ajax to $.getJSON. Perhaps your server isn't delivering the items.json file with the correct Content-type and jQuery is unable to determine the data type automatically. Also, how are you opening your app; via http:// or file:///? Commented Jan 31, 2018 at 3:10
  • @stevendesu, I think the code is fine. You should check if /items.json accessible. This could be your web server setup. Commented Jan 31, 2018 at 4:34

2 Answers 2

8

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, or new.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)

Sign up to request clarification or add additional context in comments.

Comments

2

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.