2017-03-02 6 views
6

Bevor ich Filmdetails vom Skript der Komponente erhielt. Die Funktion überprüft zunächst, ob die Film-ID des Geschäfts dieselbe ist wie die Param-Film-ID der Route. Wenn das selbe ist dann den Film nicht von der Server-API holen, oder den Film von der Server-API holen.

Es war in Ordnung. Aber jetzt versuche ich, die Filmdetails aus der Mutation des Ladens zu bekommen. Ich erhalte aber Fehler

Uncaught TypeError: Cannot read property '$route' of undefined

Wie vue-Router verwenden, um die ($route) params zugreifen und vue-Ressource ($http) vom Server API in vuex Laden zu bekommen?

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) 
        }); 
      } 
     }, 
    }, 
}); 

Komponente Skript:

export default { 
    computed: { 
     movie() { 
      return this.$store.state.movieDetail; 
     } 
    }, 
    created: function() { 
     this.$store.commit('checkMovieStore'); 
    }, 
} 

Antwort

5

Um $http oder $router in Ihrem vuex Speicher zu verwenden, müssten Sie die Hauptvue-Instanz verwenden. Obwohl ich das nicht empfehlen möchte, werde ich hinzufügen, was ich empfehle, nachdem ich die eigentliche Frage beantwortet habe.


In Ihrem main.js oder wo auch immer Sie Ihre vue Instanz wie schaffen:

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

oder etwas ähnliches, können Sie auch zu den vue-router und vue-resource Plugins hinzugefügt haben könnte.

eine leichte Modifikation dies zu tun:

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

Ich kann es jetzt in vuex speichert importieren wie folgt:

//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) 
    }); 
    } 
} 

und wie die Antwort von Austio geht, sollte diese Methode ein action sein wie mutations sind nicht entworfen, um async zu behandeln.


kommen nun auf die empfohlene Art und Weise, es zu tun.

  1. Ihre component können die route params zugreifen und liefern sie an die action.

    methods: { 
        ...mapActions({ 
        doSomethingPls: ACTION_NAME 
        }), 
        getMyData() { 
        this.doSomethingPls({id: this.$route.params}) 
        } 
    } 
    
  2. Die action macht dann den Anruf über eine abstrahierte API-Service-Datei (read plugins)

    [ACTION_NAME]: ({commit}, payload) { 
        serviceWhichMakesApiCalls.someMethod(method='GET', payload) 
        .then(data => { 
         // Do something with data 
        }) 
        .catch(err => { 
         // handle the errors 
        }) 
    } 
    
  3. Ihre actions einige async Job machen und das Ergebnis in eine mutation bereitzustellen.

    serviceWhichMakesApiCalls.someMethod(method='GET', payload) 
        .then(data => { 
         // Do something with data 
         commit(SOME_MUTATION, data) 
        }) 
        .catch(err => { 
         // handle the errors 
        }) 
    
  4. Mutations sollten die Einzigen sein, um Ihre state zu ändern.

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

Beispiel Eine Datei, die eine Liste von Endpunkten enthält, könnten Sie es brauchen, wenn Sie verschiedene Stadien der Einsatz haben, die wie andere api Endpunkte: Test, Staging, Produktion,

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

Und die Hauptdatei, die Vue.http als Dienst implementiert:

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) } 
} 

Der QueryAdder, falls es wichtig ist, habe ich verwendet, um Parameter zur URL hinzuzufügen.

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 
} 
+0

Ich habe eine Variable verwendet, um auf die Hauptvue-Instanz in einer Aktion zu verweisen. Diese Aktion wird während des erstellten Hooks einer Komponente aufgerufen. Zu diesem Zeitpunkt ist der Verweis auf die Hauptvue-Instanz nicht verfügbar, was zu einer Ausnahme führt. – Teddy

+0

Dies geschieht nur, wenn diese Komponente zuerst auf dieser Route geladen wird, wenn der Benutzer auf die Schaltfläche zum erneuten Laden des Browsers klickt. Wenn die App bereits geladen ist, funktioniert die Navigation zu dieser Komponente einwandfrei. Gibt es in diesem Fall eine Problemumgehung? – Teddy

+0

TypeError: Kann die Eigenschaft '$ http' von undefined nicht lesen – Teddy

2

So ein paar Dinge, die $ Speicher und $ route sind Eigenschaften der Instanz Vue, weshalb sie den Zugriff innerhalb von Vuex-Instanz funktioniert nicht. Auch sind Mutationen synchonous, was Sie brauchen, sind Aktionen

  1. Mutationen => Eine Funktion, Zustand gegeben und einige Argumente, die den Zustand

  2. Aktion mutiert => Haben async Dinge wie http Anrufe und dann Ergebnisse begehen eine Mutation

Also erstellen Sie eine Aktion, die die http absetzt. Denken Sie daran, das ist Pseudocode.

//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); 
}, 

Jetzt erstellten Funktion löst die checkMovieStore Aktion mit der ID, die den HTTP-Aufruf macht, sobald dies abgeschlossen ist es den Laden mit dem Wert aktualisiert.

Verwandte Themen