如何在 vuex 商店中使用 vue-resource ($http) 和 vue-router ($route)?
Posted
技术标签:
【中文标题】如何在 vuex 商店中使用 vue-resource ($http) 和 vue-router ($route)?【英文标题】:How to use vue-resource ($http) and vue-router ($route) in a vuex store? 【发布时间】:2017-07-22 11:13:50 【问题描述】:在我从组件的脚本中获取电影细节之前。该函数首先检查商店的电影 ID 是否与路由的 param 电影 ID 相同。如果相同,则不要从服务器 API 获取电影,否则从服务器 API 获取电影。
工作正常。但现在我正试图从商店的突变中获取电影细节。但是我收到错误
未捕获的类型错误:无法读取未定义的属性“$route”
如何使用 vue-router ($route)
访问参数和 vue-resource ($http)
从 vuex store 中的服务器 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');
,
【问题讨论】:
【参考方案1】:在您的 vuex 商店中:
import Vue from 'vue'
Vue.http.post('url',)
不像普通的 vue 组件:
this.$http.post(...)
【讨论】:
【参考方案2】:我强烈建议在 vuex 模块(存储和子模块)上导入 axios,并将其用于您的 http 请求
【讨论】:
为什么?我不明白为什么axios
总是 是更好的答案。您能否解释为什么 axios 在这种特殊情况下更好?
主要原因是社区,您会发现更容易找到解决此类问题的方法。
也许,我的意思是:也许提供为什么你向人们实际询问的人推荐另一个库。如果你问“我的车抛锚了,有人可以帮忙吗?”你会怎么想?有人走过来说“你应该换一辆不同的车”。
也许链接到这样的东西:medium.com/the-vue-point/retiring-vue-resource-871a82880af4【参考方案3】:
要访问商店中的 vue 实例,请使用 this._vm
。
但正如 Amresh 建议的那样,不要在 vuex 中使用 $router
之类的东西
【讨论】:
【参考方案4】:要在您的 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 实例。在组件的创建钩子期间调用该操作。那个时候对主vue实例的引用不可用,导致异常。 只有当该组件恰好是该路由上加载的第一个组件时,当用户单击浏览器重新加载按钮时,才会发生这种情况。如果应用程序已经加载,导航到该组件可以正常工作。这种情况有什么解决方法吗? 你试过我添加的推荐方法了吗?使用实例并不是使用 $http 的好方法。 我还没想好怎么做。一些官方示例使用了 store 和 api 服务,但他们只使用了 mocks 而不是 http 请求。有可用的链接吗? YourVueInstance.$http 不起作用,但 Vue.http 以某种方式工作【参考方案5】:所以有些东西,$store 和 $route 是 Vue 实例的属性,这就是为什么在 Vuex 实例内部访问它们不起作用的原因。此外,突变是同步的,你需要的是行动
Mutations => 一个给定状态和一些参数的函数会改变状态
Action => 执行异步操作,例如 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 商店中使用 vue-resource ($http) 和 vue-router ($route)?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Nuxt 和 Jest 在 Vuex 商店测试中访问 this.app 和/或注入插件
如何在 natviescript-vue vuex 商店操作中使用 $navigateTo?