【问题标题】:How to use vue-resource ($http) and vue-router ($route) in a vuex store?如何在 vuex 商店中使用 vue-resource ($http) 和 vue-router ($route)?
【发布时间】: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');
    },
}

【问题讨论】:

    标签: javascript vuejs2 vue-router vue-resource vuex


    【解决方案1】:

    在您的 vuex 商店中:

    import Vue from 'vue'
    
    Vue.http.post('url',{})
    

    不像普通的 vue 组件: this.$http.post(...)

    【讨论】:

      【解决方案2】:

      我强烈建议在 vuex 模块(存储和子模块)上导入 axios,并将其用于您的 http 请求

      【讨论】:

      • 为什么?我不明白为什么axios 总是 是更好的答案。您能否解释为什么 axios 在这种特殊情况下更好?
      • 主要原因是社区,您会发现更容易找到解决此类问题的方法。
      • 也许,我的意思是:也许提供为什么你向人们实际询问的人推荐另一个库。如果你问“我的车抛锚了,有人可以帮忙吗?”你会怎么想?有人走过来说“你应该换一辆不同的车”。
      【解决方案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-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 以防万一它很重要,我用它来向 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 实例内部访问它们不起作用的原因。此外,突变是同步的,你需要的是行动

        1. Mutations => 一个给定状态和一些参数的函数会改变状态

        2. 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 调用,一旦完成,它会使用值更新商店。

        【讨论】:

          猜你喜欢
          • 2017-12-18
          • 2021-12-05
          • 2019-08-18
          • 1970-01-01
          • 2020-01-10
          • 2023-03-24
          • 2019-10-27
          • 2021-10-20
          • 2017-04-02
          相关资源
          最近更新 更多