[Vuejs]-Where should component fetch logic be placed?

3👍

The ready() hook does not exist in Vue.js 2.

You could place your Ajax code in many hooks. It is more common to use one of the following lifecycle hooks:

  • beforeCreate()
  • created()
  • beforeMount()
  • mounted().

What should guide your decision, then? There’s somethings you must consider.

First: Vue’s initialization code is executed synchronously.

This means, technically, any asynchronous code you run in any of those hooks will only respond after all of those hooks end. See demo:

new Vue({
  el: '#app',
  beforeCreate() {
    setTimeout(() => { console.log('fastest asynchronous code ever (started at beforeCreate)') }, 0);
    console.log('beforeCreate hook executed');
  },
  created() {
    console.log('created hook executed');
  },
  beforeMount() {
    console.log('beforeMount hook executed');
  },
  mounted() {
    console.log('mounted hook executed');
  }
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<div id="app">
  Check the console.
</div>

In other words, if you make an Ajax call in beforeCreate, no matter how fast the API responds, the response will only be processed way later, way after the created() has been executed.

Which hook to use?

When using Vuex to manage state globally

As mentioned in comments, a common approach is to use Vuex to manage your application’s state globally. In that case, the requests should be started in Vuex actions. Your component, then, in any lifecycle hook (or method), would dispatch the actions. See demo below.

const store = new Vuex.Store({
strict: true,
  state: {
    people: []
  },
  mutations: {
    populate: function (state, newPeople) {
      state.people = newPeople
    }
  },
  actions: {
    fetchPeople ({ commit }) {
      axios.get('https://reqres.in/api/users').then(function (response) {
        commit('populate', response.data.data)
      }, function () {
        console.log('error')
      })
    }
  }
});

Vue.component('mycomp', {
  computed: Vuex.mapState(['people']),
  template: `
    <ul>
      <li v-for="p in people">
      {{ p.first_name }} {{ p.last_name }}
      </li>
    </ul>
  `
});

new Vue({
  store,
  el: '#app',
  created() {
    this.$store.dispatch('fetchPeople');
  },
  computed: Vuex.mapState(['people']),
})
<script src="https://unpkg.com/vue"></script>
<script src="https://unpkg.com/vuex"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>

<div id="app">
  In parent:
  <ul>
    <li v-for="p in people">
      {{ p.first_name }} {{ p.last_name }}
    </li>
  </ul>
  <hr>
  In custom component (the very same data, fetched only once):
  <mycomp></mycomp>
</div>

Leave a comment