How to use vue-resource ($ http) and vue-router ($ route) in vuex repository?

Before I got the movie details from the script component. First, the function checks whether the movie identifier in the store is the same as the movie identifier of the route parameters. If this is the same, you won’t get the movie from the server API, or get the movie from the server API.

It worked fine. But now I'm trying to get movie details from a store mutation. However i get an error

Uncaught TypeError: Cannot read property '$ route' undefined

How to use vue-router ($route) to access parameters and vue-resource ($http) to get from the server API in the vuex repository?

store.js:

 export default new Vuex.Store({ state: { movieDetail: {}, }, mutations: { checkMovieStore(state) { const routerMovieId = this.$route.params.movieId; const storeMovieId = state.movieDetail.movie_id; if (routerMovieId != storeMovieId) { let url = "http://dev.site.com/api/movies/movie-list/" + routerMovieId + "/"; this.$http.get(url) .then((response) => { state.movieDetail = response.data; }) .catch((response) => { console.log(response) }); } }, }, }); 

script component:

 export default { computed: { movie() { return this.$store.state.movieDetail; } }, created: function () { this.$store.commit('checkMovieStore'); }, } 
+6
source share
2 answers

To use $http or $router in your vuex repository, you will need to use the main vue instance. Although I do not recommend using this, I will add what I recommend after answering the actual question.


In your main.js or wherever you create your vue instance, for example:

 new Vue({ el: '#app', router, store, template: '<App><App/>', components: { App } }) 

or something similar, you can also add vue-router and vue-resource plugins.

After making a small change:

 export default new Vue({ el: '#app', router, store, template: '<App><App/>', components: { App } }) 

Now I can import it into vuex repositories as follows:

 //vuex store: import YourVueInstance from 'path/to/main' checkMovieStore(state) { const routerMovieId = YourVueInstance.$route.params.movieId; const storeMovieId = state.movieDetail.movie_id; if (routerMovieId != storeMovieId) { let url = "http://dev.site.com/api/movies/movie-list/" + routerMovieId + "/"; YourVueInstance.$http.get(url) .then((response) => { state.movieDetail = response.data; }) .catch((response) => { console.log(response) }); } } 

and as Austio's answer , this method should be action , since mutations not meant to handle async.


Now let's get to the recommended way to do this.

  • Your component can access route params and provide its action .

     methods: { ...mapActions({ doSomethingPls: ACTION_NAME }), getMyData () { this.doSomethingPls({id: this.$route.params}) } } 
  • Then action makes a call through an abstract API service file ( read plugins )

     [ACTION_NAME]: ({commit}, payload) { serviceWhichMakesApiCalls.someMethod(method='GET', payload) .then(data => { // Do something with data }) .catch(err => { // handle the errors }) } 
  • Your actions do some asynchronous task and provide a mutation result.

     serviceWhichMakesApiCalls.someMethod(method='GET', payload) .then(data => { // Do something with data commit(SOME_MUTATION, data) }) .catch(err => { // handle the errors }) 
  • mutations should be the only ones who can change your state .

     [SOME_MUTATION]: (state, payload) { state[yourProperty] = payload } 

Example A file containing a list of endpoints may be required if you have different deployment steps that have different api endpoints, such as: test, staging, production, etc.

 export const ENDPOINTS = { TEST: { URL: 'https://jsonplaceholder.typicode.com/posts/1', METHOD: 'get' } } 

And the main file that implements Vue.http as a service:

 import Vue from 'vue' import { ENDPOINTS } from './endpoints/' import { queryAdder } from './endpoints/helper' /** * - ENDPOINTS is an object containing api endpoints for different stages. * - Use the ENDPOINTS.<NAME>.URL : to get the url for making the requests. * - Use the ENDPOINTS.<NAME>.METHOD : to get the method for making the requests. * - A promise is returned BUT all the required processing must happen here, * the calling component must directly be able to use the 'error' or 'response'. */ function transformRequest (ENDPOINT, query, data) { return (ENDPOINT.METHOD === 'get') ? Vue.http[ENDPOINT.METHOD](queryAdder(ENDPOINT.URL, query)) : Vue.http[ENDPOINT.METHOD](queryAdder(ENDPOINT.URL, query), data) } function callEndpoint (ENDPOINT, data = null, query = null) { return new Promise((resolve, reject) => { transformRequest(ENDPOINT, query, data) .then(response => { return response.json() }) .then(data => { resolve(data) }) .catch(error => { reject(error) }) }) } export const APIService = { test () { return callEndpoint(ENDPOINTS.TEST) }, login (data) { return callEndpoint(ENDPOINTS.LOGIN, data) } } 

RequestAdder in case this is important, I used this to add params to the url.

 export function queryAdder (url, params) { if (params && typeof params === 'object' && !Array.isArray(params)) { let keys = Object.keys(params) if (keys.length > 0) { url += `${url}?` for (let [key, i] in keys) { if (keys.length - 1 !== i) { url += `${url}${key}=${params[key]}&` } else { url += `${url}${key}=${params[key]}` } } } } return url } 
+5
source

Thus, $ store and $ route are properties of the Vue instance, so accessing them inside the Vuex instance does not work. In addition, mutations are synchronous, what you need is actions

  • Mutations => A function that sets state and some arguments changes state

  • Action => Take asynchronous actions like http calls and then commit the mutation results

So, create an action that sends http. Keep in mind that this is pseudo code.

 //action in store checkMovieStore(store, id) { return $http(id) .then(response => store.commit({ type: 'movieUpdate', payload: response }) } //mutation in store movieUpdate(state, payload) { //actually set the state here Vue.set(state.payload, payload) } // created function in component created: function () { return this.$store.dispatch('checkMovieStore', this.$route.params.id); }, 

Now your created function sends a checkMovieStore action with an identifier that makes an HTTP call, after it completes, it updates the store with a value.

+2
source

Source: https://habr.com/ru/post/1015413/


All Articles