Vuex: How to use Resource in actions?

Created on 8 Mar 2016  路  14Comments  路  Source: vuejs/vuex

I try to use the vue-resource for an ajax request in an action.

// actions.js
export function loadData(state) {
  Vue.$http.get('api/songs').then((value) => {
    console.log('load data');

    // here come maaaany logic
  });
}

But i can't get it to work. this.$http or import Vue does not work.

Or is this way totally wrong? My goal is to load all data by start of my app:

// app.js <- main entry

// importing files...

new Vue({
  el: '#app',

  store,

  components: { /* ... */ },

  ready: function() {
    loadData(store);
  }
});

The reason why i have a lot of logic in this action is, that i will refire this action multiple times (it resets many things and fires this again).

Most helpful comment

Auth Service (services/auth.js)

import Vue from 'vue'

export default {

  authenticate(request) {

    return Vue.http.post('auth/authenticate', request)
      .then((response) => Promise.resolve(response.data))
      .catch((error) => Promise.reject(error));

  },

  // other methods
}

Vuex Auth actions (vuex/actions/auth.js)

import { AUTHENTICATE, AUTHENTICATE_FAILURE } from '../mutation-types'
import authService from '../../services/auth'

export const authenticate = (store, request) => {

  return authService.authenticate(request)
    .then((response) => store.dispatch(AUTHENTICATE, response))
    .catch((error) => store.dispatch(AUTHENTICATE_FAILURE, error));

}

// other actions

Vuex Auth module (vuex/modules/auth.js)

import { AUTHENTICATE, AUTHENTICATE_FAILURE } from '../mutation-types'
import Vue from 'vue'

// initial State
const state = {
  token: null,
  failure: null
}

// mutations
const mutations = {

  [AUTHENTICATE] (state, response) {
    state.token = response.token;
  },

  [AUTHENTICATE_FAILURE] (state, error) {
    state.failure = error;
  },

  // other mutations

}

export default {
  state,
  mutations
}

Vuex mutation types (vuex/mutation-types.js)

export const AUTHENTICATE = 'AUTHENTICATE'
export const AUTHENTICATE_FAILURE = 'AUTHENTICATE_FAILURE'

// other mutation types

Notes:

1) I'm using Promise.resolve and Promise.reject in order to chain promises, but this is not needed in all cases. (see more here)

2) You don't need to return a promise from the authenticate() action (in 'vuex/actions/auth.js'). I'm returning a promise so I can pass it to the router state, so it can wait before entering the route.

All 14 comments

Why close? I have same issue now. Not sure best place to handle that kind of scenario?

Hi @jonagoldman

It's question I'm having now. I can't find the example for that until now.

my case is I want to update mutation state (vuex store) which is { authenticated : true/false } in every request. Because I want to check for whether authenticated user exists or not from components .

So I have to used with beforeEach from vue-router in main.js. the thing is I can't access mutation store from main.js. And I want to know where is the most appropriate place to put vue-resource logic. eg. in store/actions.js (or) store.js (or) keep like that?

// main.js
var Vue = require('vue');
var VueRouter = require('vue-router');
var VueResource = require('vue-resource');
var Vuex = require('vuex');

Vue.use(VueRouter);
Vue.use(VueResource);

Vue.config.debug = false;
Vue.config.silent = true;

Vue.http.headers.common['X-CSRF-TOKEN'] = $('meta[name="token"]').attr('value');

var router = new VueRouter;

import Home from './frontend/home.vue';
import { checkAuth } from './vuex/actions'

var App = Vue.extend({})

var router = new VueRouter({
    hashbang: false
})

router.beforeEach(function(transition) {
    this.http.get('/auth/status').then(function(data) {
        checkAuth(); // want to update the auth status from here to vuex store which I can't now
        transition.next()
    }).catch(function (data, status, request) {
        // handle error.
    });
}.bind(Vue))

// App routes.
router.map({
    '/' : {
        component: Home
    },
    '*': {
        component: require('./components/not-found.vue')
    }
})

router.start(App, '#app')

@webcrazy I don't exactly understand the problem, but a few things come to mind:

1) You don't need to update the state in every request. Just check the state to see if the user is authenticated. This can be done inside components. You can also share getters across multiple components if needed.

2) You can import the store anywhere you need it using a regular import store from './store'.

3) If you need to check something in every mutation, you can use a Middleware.

4) If you need to do something in every request, you should use Interceptors.

5) I recommend abstracting requests to an api service. Meaning take all of your this.http.get('/xxx') to different files. And the doing XXXService.get()

6) Take a look at the examples and use them as a guide.

I know I'm not being too specific, but I hope it helps.

@jonagoldman

Thanks a lot for your info. I'll try them.

@jonagoldman any example for this point?

5) I recommend abstracting requests to an api service. Meaning take all of your this.http.get('/xxx') to different files. And the doing XXXService.get()

Thanks

Auth Service (services/auth.js)

import Vue from 'vue'

export default {

  authenticate(request) {

    return Vue.http.post('auth/authenticate', request)
      .then((response) => Promise.resolve(response.data))
      .catch((error) => Promise.reject(error));

  },

  // other methods
}

Vuex Auth actions (vuex/actions/auth.js)

import { AUTHENTICATE, AUTHENTICATE_FAILURE } from '../mutation-types'
import authService from '../../services/auth'

export const authenticate = (store, request) => {

  return authService.authenticate(request)
    .then((response) => store.dispatch(AUTHENTICATE, response))
    .catch((error) => store.dispatch(AUTHENTICATE_FAILURE, error));

}

// other actions

Vuex Auth module (vuex/modules/auth.js)

import { AUTHENTICATE, AUTHENTICATE_FAILURE } from '../mutation-types'
import Vue from 'vue'

// initial State
const state = {
  token: null,
  failure: null
}

// mutations
const mutations = {

  [AUTHENTICATE] (state, response) {
    state.token = response.token;
  },

  [AUTHENTICATE_FAILURE] (state, error) {
    state.failure = error;
  },

  // other mutations

}

export default {
  state,
  mutations
}

Vuex mutation types (vuex/mutation-types.js)

export const AUTHENTICATE = 'AUTHENTICATE'
export const AUTHENTICATE_FAILURE = 'AUTHENTICATE_FAILURE'

// other mutation types

Notes:

1) I'm using Promise.resolve and Promise.reject in order to chain promises, but this is not needed in all cases. (see more here)

2) You don't need to return a promise from the authenticate() action (in 'vuex/actions/auth.js'). I'm returning a promise so I can pass it to the router state, so it can wait before entering the route.

@jonagoldman Thanks a lot for your example and detail explanation :+1:

This deserves to be in examples

I agree, these should be in the examples... I just spent an hour trying to find the best way of integrating vue-resource. Thanks for the example @jonagoldman

fyi
the solution doesn't work if there's an alias in _webpack.config.js_

    resolve: {
        alias: {
            vue: 'vue/dist/vue.js'
        }
    }

I used a quick&dirty way to solve this:

import Vue from 'vue'

const Http = new Vue
Http.get('').then() ...

mark the idea of service really helpful.

@buzdykg fails without the alias too but the trick works. Thanks.

The error in my case is '_vue2.default' is undefined in '_vue2.default.$http...'

Any idea why it fails?

@jonagoldman
you example is very good! but in components how get vue-resource Promise, i hope some page action write in to, but always get in then(), I hope use catch() in the components.

I am using vue like one day, so I do not understand half of things written there.

I imported vue and vuex to my wordpress project and got $http undefined. As I understand from posts, ajax client is not part of vue nor vuex and that vue-resorce is outdated. So I just changed 'this.$http.get()' for 'axios.get()'

This helped - https://vuejsexamples.net/vuejs-ajax/

Was this page helpful?
0 / 5 - 0 ratings

Related issues

jdittrich picture jdittrich  路  3Comments

taoeffect picture taoeffect  路  3Comments

jskrzypek picture jskrzypek  路  3Comments

haoxins picture haoxins  路  4Comments

gdelazzari picture gdelazzari  路  3Comments