tejoprabowo
tejoprabowo

Reputation: 897

how to get data from API in vuex using axios?

I have data taken from API laravel, and here is my code in state.js

import axios from 'axios'
import {apiPostGet} from '../api/api'
export default {
  data: axios({
    method: 'GET',
    url: apiPostGet('Kategori')
  }).then(
    response => {
      return response.data.kategori
    }
  ).catch(
    error => {
      return error.response
    }
  )
}

and this is my code in gteeters.js

export default {
  datas: state => {
    return state.data
  }
}

and this is my code in index.js

import Vue from 'vue'
import Vuex from 'vuex'
import state from './state'
import getters from './getters'

Vue.use(Vuex)

export default new Vuex.Store({
   state,
   getters
})

and this picture from dev tool vue js

Upvotes: 15

Views: 32274

Answers (2)

Yordan Georgiev
Yordan Georgiev

Reputation: 5460

I would use the solution of the AWolf, however with a slightly improved error handling in the loadData method

<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
  function getUrlParams() {
    var url_params = new URLSearchParams();
    if (window.location.toString().indexOf("?") != -1) {
      var href_part = window.location.search.split('?')[1]
      href_part.replace(/([^=&]+)=([^&]*)/g,
        function(m, key, value) {
          var attr = decodeURIComponent(key)
          var val = decodeURIComponent(value)
          url_params.append(attr, val);
        });
    }
    // for(var pair of url_params.entries()) { consolas.log(pair[0]+ '->'+ pair[1]); }
    return url_params;
  }


  function getServerData(url, urlParams) {
    if (typeof url_params == "undefined") {
      urlParams = getUrlParams()
    }
    return axios.get(url, {
        params: urlParams
      })
      .then(response => {
        return response;
      })
      .catch(function(error) {
        console.error(error)
        return error.response;
      })
  }

  // Action !!!
  getServerData(url, url_params)
    .then(response => {
      if (response.status === 204) {
        var warningMsg = response.statusText
        console.warn(warningMsg)
        return
      } else if (response.status === 404 || response.status === 400) {
        var errorMsg = response.statusText // + ": "  + response.data.msg // this is my api
        console.error(errorMsg)
        return;
      } else {
        var data = response.data
        var dataType = (typeof data)
        if (dataType === 'undefined') {
          var msg = 'unexpected error occurred while fetching data !!!'
          // pass here to the ui change method the msg aka
          // showMyMsg ( msg , "error")
        } else {
          var items = data.dat // obs this is my api aka "dat" attribute - that is whatever happens to be your json key to get the data from
          // call here the ui building method
          // BuildList ( items )
        }
        return
      }
    })
</script>

Upvotes: 0

AWolf
AWolf

Reputation: 8990

Data hook needs to return synchronously. You have to add the loading to created or mounted and just add the properties to data / state, so reactivity is working.

The loading of the data with Axios needs to be triggerd with an action because it's asynch. Mutations need to run synchronous. I've added the initial loading in created. (mounted would also work.)

I've used the Vuex helper mapState to map the state properties to the component. Using getters would also work but mapState is easier to write.

Please have a look at the demo below or this fiddle.

Also uncomment the code below the Vuex version in the fiddle and comment the app above to see how Axios is working with-out Vuex for a better understanding.

const URL = 'https://jsonplaceholder.typicode.com/posts';

const store = new Vuex.Store({
  state: {
    posts: [],
    loading: true
  },
  actions: {
    loadData({
      commit
    }) {
      axios.get(URL).then((response) => {
        // console.log(response.data, this)
        commit('updatePosts', response.data)
        commit('changeLoadingState', false)
      })
    }
  },
  mutations: {
    updatePosts(state, posts) {
      state.posts = posts
    },
    changeLoadingState(state, loading) {
      state.loading = loading
    }
  }
})

new Vue({
  el: '#app',
  computed: Vuex.mapState(['posts', 'loading']),
  store,
  created() {
    //console.log(this.$store)
    this.$store.dispatch('loadData') // dispatch loading
  }
})

/*
	//example with-out vuex
  
new Vue({
	el: '#app',
	data() {
  	return {
    	loading: true,
      posts: [] // add posts here so reactivity is working, also undefined would be OK
    }
  },
  created() {
  	//this.loading = true --> not needed already set in data
  	axios.get(URL).then((response) => {
    	// console.log(response.data, this)
      this.posts = response.data
      this.loading = false
    })
  }
})

*/
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.13/vue.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vuex/3.0.1/vuex.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.17.1/axios.js"></script>
<div id="app">
  <div v-if="loading">
    loading...
  </div>
  <div v-else>
    <ul>
      <li v-for="post in posts">
        <h1>
          {{post.title}}
        </h1>
        <p>
          {{post.body}}
        </p>
      </li>
    </ul>
  </div>
</div>

Upvotes: 30

Related Questions