如何在vuex商店中使用vue-resource($ http)和vue-router($ route)?

时间:2017-03-02 16:06:55

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

在我从组件的脚本中获取电影细节之前。该功能首先检查商店的电影ID是否与路线的参数电影ID相同。如果相同则不从服务器API获取电影,或者从服务器API获取电影。

工作正常。但现在我正试图从商店的变异中获取电影细节。但是我收到错误

  

未捕获的TypeError:无法读取属性' $ route'未定义的

如何使用vue-router ($route)访问params和vue-resource ($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 个答案:

答案 0 :(得分:12)

要在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
    }
    
  5. 示例 包含端点列表的文件,如果您具有不同的api端点,例如:test,staging,production等,则可能需要它们。

    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,如果它很重要,我用它来将params添加到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
    }
    

答案 1 :(得分:1)

所以有一些东西,$ store和$ route是Vue实例的属性,这就是为什么在Vuex实例中访问它们不起作用的原因。此外,突变是同步的,你需要的是行动

  1. 突变=&gt;给定状态和一些参数的函数会改变状态

  2. 动作=&gt;执行像http调用之类的异步操作,然后将结果提交到突变

  3. 所以创建一个调度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操作,该ID执行http调用,一旦完成,它将使用值更新商店。

答案 2 :(得分:1)

在vuex商店中:

import Vue from 'vue'

Vue.http.post('url',{})

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

答案 3 :(得分:0)

要访问商店中的vue实例,请使用add_action( 'rest_api_init' , 'wt_rest_api'); function wt_rest_api(){ register_rest_route('wtrest','events',array( 'methods' => WP_REST_SERVER::READABLE, 'callback' => 'wtEventResults' )); } function wtEventResults($data){ $events = new WP_Query([ 'post_type' => 'event', 'post__in' => array( (int)$data['id'] ) ]); $eventsResults = []; while($events->have_posts()){ $events->the_post(); array_push($eventsResults , [ 'content' => apply_filters( 'the_content' , get_the_content()) ]); } return $eventsResults; }
但正如Amresh建议,请勿在vuex中使用this._vm之类的东西

答案 4 :(得分:0)

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