如何在 vuex 商店中使用 vue-resource ($http) 和 vue-router ($route)?
How to use vue-resource ($http) and vue-router ($route) in a vuex store?
在我从组件的脚本中获取电影细节之前。该函数首先检查商店的电影 ID 是否与路由的参数电影 ID 相同。如果相同则不要从服务器 API 获取电影,否则从服务器 API.
获取电影
它运行良好。但现在我正试图从商店的突变中获取电影细节。但是我收到错误
Uncaught TypeError: Cannot read property '$route' of undefined
如何使用 vue-router ($route)
访问参数和 vue-resource ($http)
从服务器 API 在 vuex store 中获取?
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');
},
}
有几点,$store 和 $route 是 Vue 实例的属性,这就是为什么在 Vuex 实例内部访问它们不起作用的原因。此外,突变是同步的,你需要的是动作
Mutations => 给定状态和一些参数改变状态的函数
操作 => 执行异步操作,例如 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 调度 checkMovieStore 操作,它执行 http 调用,一旦完成,它就会使用值更新商店。
要在您的 vuex 商店中使用 $http
或 $router
,您需要使用主 vue 实例。虽然我不推荐使用这个,但我会在回答实际问题后添加我推荐的内容。
在您的 main.js
中或您创建 vue 实例的任何地方,例如:
new Vue({
el: '#app',
router,
store,
template: '<App><App/>',
components: {
App
}
})
或类似的东西,您可能还添加了 vue-router
和 vue-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
不是为处理异步而设计的。
现在介绍推荐的方法。
您的 component
可以访问 route params
并将其提供给 action
。
methods: {
...mapActions({
doSomethingPls: ACTION_NAME
}),
getMyData () {
this.doSomethingPls({id: this.$route.params})
}
}
然后 action
通过抽象的 API 服务文件 (read plugins
)
进行调用
[ACTION_NAME]: ({commit}, payload) {
serviceWhichMakesApiCalls.someMethod(method='GET', payload)
.then(data => {
// Do something with data
})
.catch(err => {
// handle the errors
})
}
你的 actions
做一些异步工作并将结果提供给 mutation
.
serviceWhichMakesApiCalls.someMethod(method='GET', payload)
.then(data => {
// Do something with data
commit(SOME_MUTATION, data)
})
.catch(err => {
// handle the errors
})
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 万一它很重要,我用它来将参数添加到 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
}
要访问商店中的 vue 实例,请使用 this._vm
。
但正如 Amresh 建议的那样,不要在 vuex
中使用 $router
之类的东西
我强烈建议在 vuex 模块(商店和子模块)上导入 axios,并将其用于您的 http 请求
在你的 vuex 商店中:
import Vue from 'vue'
Vue.http.post('url',{})
不像普通的 vue 组件:
this.$http.post(...)
在我从组件的脚本中获取电影细节之前。该函数首先检查商店的电影 ID 是否与路由的参数电影 ID 相同。如果相同则不要从服务器 API 获取电影,否则从服务器 API.
获取电影它运行良好。但现在我正试图从商店的突变中获取电影细节。但是我收到错误
Uncaught TypeError: Cannot read property '$route' of undefined
如何使用 vue-router ($route)
访问参数和 vue-resource ($http)
从服务器 API 在 vuex store 中获取?
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');
},
}
有几点,$store 和 $route 是 Vue 实例的属性,这就是为什么在 Vuex 实例内部访问它们不起作用的原因。此外,突变是同步的,你需要的是动作
Mutations => 给定状态和一些参数改变状态的函数
操作 => 执行异步操作,例如 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 调度 checkMovieStore 操作,它执行 http 调用,一旦完成,它就会使用值更新商店。
要在您的 vuex 商店中使用 $http
或 $router
,您需要使用主 vue 实例。虽然我不推荐使用这个,但我会在回答实际问题后添加我推荐的内容。
在您的 main.js
中或您创建 vue 实例的任何地方,例如:
new Vue({
el: '#app',
router,
store,
template: '<App><App/>',
components: {
App
}
})
或类似的东西,您可能还添加了 vue-router
和 vue-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
不是为处理异步而设计的。
现在介绍推荐的方法。
您的
component
可以访问route params
并将其提供给action
。methods: { ...mapActions({ doSomethingPls: ACTION_NAME }), getMyData () { this.doSomethingPls({id: this.$route.params}) } }
然后
进行调用action
通过抽象的 API 服务文件 (readplugins
)[ACTION_NAME]: ({commit}, payload) { serviceWhichMakesApiCalls.someMethod(method='GET', payload) .then(data => { // Do something with data }) .catch(err => { // handle the errors }) }
你的
actions
做一些异步工作并将结果提供给mutation
.serviceWhichMakesApiCalls.someMethod(method='GET', payload) .then(data => { // Do something with data commit(SOME_MUTATION, data) }) .catch(err => { // handle the errors })
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 万一它很重要,我用它来将参数添加到 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
}
要访问商店中的 vue 实例,请使用 this._vm
。
但正如 Amresh 建议的那样,不要在 vuex
$router
之类的东西
我强烈建议在 vuex 模块(商店和子模块)上导入 axios,并将其用于您的 http 请求
在你的 vuex 商店中:
import Vue from 'vue'
Vue.http.post('url',{})
不像普通的 vue 组件:
this.$http.post(...)