Skip to content

Instantly share code, notes, and snippets.

@guanzo
Last active March 28, 2023 07:19
Show Gist options
  • Star 39 You must be signed in to star a gist
  • Fork 11 You must be signed in to fork a gist
  • Save guanzo/6e334b62e6660450eabd112c2bc98350 to your computer and use it in GitHub Desktop.
Save guanzo/6e334b62e6660450eabd112c2bc98350 to your computer and use it in GitHub Desktop.

Async calls

<template>
<!-- 
When isLoading is true, the <div> is in the DOM, the <p> is not.
When isLoading is false, Vue will remove the <div> and add the <p> to the DOM,
at which point <MyComponent> will be created and passed the fetched data.
-->
<div v-if="isLoading">
  Loading...
  {{ myData.if.you.try.to.access.properties.here.it.will.error }}
</div>
<p v-else>
  {{ myData.you.can.access.properties.now.that.myData.is.loaded }}
  <MyComponent :data="myData.you.can.pass.data.to.components.now"/>
</p>
</template>

<script>
export default {
  data: () => ({
    isLoading: false,
    myData: null,
  }),
  async created () {
    try {
      this.isLoading = true
      await this.fetchData()
      // Make sure to handle errors :)
    } finally {
      this.isLoading = false
    }
  },
  methods: {
    async fetchData () {
      const res = await axios.get('/api/myData')
      this.myData = res.data.myData
    }
  }
}
</script>

WTF is "this"??

Save yourself hours of pain, and learn how "this" works.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

<script>
export default {
  data () {
    return {
      goodData: this.goodMethod()  // this == vue
    }
  },
  data: function () {
    return {
      goodData: this.goodMethod()  // this == vue
    }
  }
  data: vm => ({
    badData: this.badMethod(), // this == window
    goodData: vm.goodMethod()  // vm == vue
  }),
  computed: {
    badComputed: () => this.badData, // this == window
    goodComputed: vm => vm.goodData, // vm == vue
    goodComputed2 () {
      console.log(this) // vue
    }
    goodComputed3: function () {
      console.log(this) // vue
    },
    goodComputed4: {
      get: vm => vm.goodData, // vm == vue
      set(val) {
        this.goodData = val  // this == vue
      }
    }
  },
  methods: {
    badMethod: () => {
      console.log(this) // window
    },
    goodMethod () {
      console.log(this) // vue
    },
    goodMethod2: function () {
      console.log(this) // vue
    },
    // Function doesn't reference "this", so an arrow function is fine here.
    doesntMatter: () => 1 + 1
  },
  mounted: () => {
    console.log(this) // window
  },
  watch: {
    badData: () => {
      console.log(this) // window
    }
  },
  created () {
    // BAD
    // The "function" keyword affects the value of "this".
    axios.get().then(function (response) {
      console.log(this) // window
    })

    // GOOD
    // An arrow function causes the function to inherit the "this" value from the
    // parent scope, in this case, the scope of the created() function.
    axios.get().then(response => {
      console.log(this) // vue
    })

    // GOOD
    // Prefer arrow functions, but saving the value of "this" in a higher scope will also work.
    const self = this
    axios.get().then(function (response) {
      console.log(this) // window
      console.log(self) // vue
    })

    // BAD
    // Obviously this doesn't just apply to axios callbacks, it applies to any callback.
    setTimeout(function () {
      console.log(this) // window
    }, 0)

    // GOOD
    setTimeout(() => {
      console.log(this) // vue
    }, 0)

    // You can avoid some of these "gotchas" with async/await, refer to the
    // fetchData() method in the earlier "Async calls" section.
  },
}
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment