web-dev-qa-db-ja.com

vuexストアでvue-resource($ http)とvue-router($ route)を使用するにはどうすればよいですか?

コンポーネントのスクリプトから映画の詳細を取得する前。この関数はまず、ストアのムービーIDがルートのパラメータームービーIDと同じであるかどうかを確認します。同じ場合は、サーバーAPIから映画を取得しないか、サーバーAPIから映画を取得します。

正常に動作していました。しかし今、私は店の突然変異から映画の詳細を取得しようとしています。しかし、私はエラーが発生しています

Uncaught TypeError:未定義のプロパティ '$ route'を読み取れません

Vue-routerの使用方法($route)パラメータと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');
    },
}
10

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である必要があります。


今それを行うための推奨される方法に来ています。

  1. componentroute 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
}
16

したがって、$ storeと$ routeはVueインスタンスのプロパティであるため、Vuexインスタンス内でそれらにアクセスすることはできません。また、ミューテーションは同期しています。必要なのはアクションです。

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

これで、作成した関数は、http呼び出しを行うidを使用してcheckMovieStoreアクションをディスパッチします。これが完了すると、ストアが値で更新されます。

2
Austio

axios をvuexモジュール(ストアとサブモジュール)にインポートし、それをhttpリクエストに使用することを強くお勧めします

0
David Soler

ストア内のvueインスタンスにアクセスするには、this._vmを使用します。
しかし、Amreshがアドバイスしたように、vuexでは$routerのようなものを使用しないでください

0
NaN