Search code examples
javascriptvue.jsasynchronousvue-component

Usage of asynchronous response data in asynchronous components


Below is the parent component and child component:

export default {
    name : 'parentNode',
    mounted: function () {
        var that = this;

        if (that.$store.state.auth.isAuthenticated) {
        
            that.$store.dispatch(ActionsType.GET_ALLCOINLIST).then(function (data) {
            // I want to use this store data in child components.
                that.$store.state.main.data = data;
            });
        }
    },
};

export default {
    name : 'childNode',
    data : function(){
        return {
            childData : {}
        }
    },
    mounted : function(){
        //How should I check if the data is loaded or not?
    },
    computed : {
        childData : function(){
            return this.$store.state.main.data;
        }
    },
    watch : {
        childData : function(){
            this.makeChart();
        }
    },
    methods : {
        makeChart : function(){
            console.log('this function make a chart.');
        }
    }
}

I want to draw a new chart whenever the $store(vuex) data changes. However, since the response of this data is asynchronous, when the child component is loaded, it may or may not have received the data (in the parent component).

I always want to draw a chart with the data I received when the child component was initially loaded. The components of Vue are also asynchronously loaded, so in this case, how can I control it? As of now, if the child component is initially loaded, the chart may or may not be drawn.


Solution

  • You can use mapState() and watch():

    import Vue from "https://cdn.skypack.dev/vue@2.6.14";
    import * as vuex from "https://cdn.skypack.dev/vuex@3.6.2";
    
    Vue.use(vuex)
    
    var store = new vuex.Store({
      state: {
        count: 1,
        isLoaded: false, // mutate that when async call is finished
      },
      mutations: {
        increment (state) {
          state.count++
        }
      },
      actions: {
        init() {
          setInterval(() => this.commit('increment'), 1000) // replace this with async call and mutate isLoaded in then()
        }
      }
    });
    
    var app = new Vue({
      el: '#app',
      store,
      data() {
        return {
        }
      }, computed: {
        ...vuex.mapState([
          'count'
        ]),
      },
        watch: {
          count() {
            console.log('watch count', this.count)
          }
        },
      mounted() {
        this.$store.dispatch('init')
      }
    })