2017-03-02 134 views
6

在我從組件的腳本獲取電影細節之前。該功能首先檢查商店的電影ID是否與路線的參數電影ID相同。如果其相同,則不從服務器API獲取電影,或者從服務器API獲取電影。

它工作正常。但現在我正試圖從商店的變化中獲得電影細節。但是我得到錯誤

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

如何使用VUE路由器($route)訪問PARAMS和VUE資源($http)從vuex存儲的服務器API獲得?

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

組件腳本:

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

回答

5

要在您的vuex商店中使用$http$router,您需要使用main vue實例。雖然我不推薦使用這個,但我會在回答實際問題後添加我推薦的內容。


在你main.js或你正在創建你的VUE實例,如:

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

或類似的東西,你可能還添加了vue-routervue-resource插件了。

做少許修改此:

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

我現在可以將其導入vuex商店像這樣:

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

,並通過Austio這個答案,這種方法應該是一個action因爲mutations不是用來處理異步的。


現在來推薦這樣做。

  1. component可以訪問route params並將其提供給action

    methods: { 
        ...mapActions({ 
        doSomethingPls: ACTION_NAME 
        }), 
        getMyData() { 
        this.doSomethingPls({id: this.$route.params}) 
        } 
    } 
    
  2. action然後通過抽象的API服務文件(read plugins

    [ACTION_NAME]: ({commit}, payload) { 
        serviceWhichMakesApiCalls.someMethod(method='GET', payload) 
        .then(data => { 
         // Do something with data 
        }) 
        .catch(err => { 
         // handle the errors 
        }) 
    } 
    
  3. 進行呼叫你actions做一些異步工作並將結果提供給mutation

    serviceWhichMakesApiCalls.someMethod(method='GET', payload) 
        .then(data => { 
         // Do something with data 
         commit(SOME_MUTATION, data) 
        }) 
        .catch(err => { 
         // handle the errors 
        }) 
    
  4. Mutations應該是唯一的修改state

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

包含端點列表的文件,如果你有部署的不同階段具有不同的API端點就像你可能需要它:測試,分期,生產等

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

並實現Vue.http作爲服務的主要文件:

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

queryAdder萬一它很重要,我正在使用它來向網址添加參數。

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

我使用了一個變量來引用動作中的主vue實例。該操作在創建組件的鉤子期間被調用。那時,主vue實例的引用不可用,這導致了一個異常。 – Teddy

+0

只有在用戶點擊瀏覽器重新加載按鈕時,該組件恰好是第一個加載在該路徑上的情況下才會發生這種情況。如果應用程序已經加載,導航到該組件工作正常。有什麼解決方法嗎? – Teddy

+0

TypeError:無法讀取未定義的屬性'$ http' – Teddy

2

那麼幾件事情,在$存儲和$路徑是在Vue的情況下,這是性質爲何訪問它們的內部Vuex實例不起作用。此外,突變是synchonous你需要的是行動

  1. 突變=>函數,鑑於國家和一些參數變異狀態

  2. 行動=>不喜歡HTTP調用異步的東西,然後提交結果突變

因此,創建一個分派http的操作。請記住這是僞代碼。現在

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

您創建的函數分派的ID,它執行HTTP調用,一旦完成它的值更新店裏checkMovieStore行動。