Как перемещаться с помощью vue router из Vuex-действий

Я создаю веб-приложение с Vue 2.x и Vuex 2.x. Я получаю некоторую информацию из удаленного места через HTTP-вызов, я хочу, чтобы, если этот вызов не удался, я должен перенаправить на другую страницу.

GET_PETS: (state) => {
  return $http.get('pets/').then((response)=>{
      state.commit('SET_PETS', response.data)
    })
  },
  error => {this.$router.push({path:"/"}) }
  )
}

Но this.$router.push({path:"/"}) дает мне следующую ошибку.

Неподготовлено (в обещании) TypeError: Не удается прочитать свойство "push" из undefined

Как это можно достичь.

Имитированный JsFiddle: здесь

Ответ 1

import router from './router'

и использовать router.push

Просто так.

Ответ 2

Похоже, вы не вводите свой роутер в свое приложение, следовательно, это "undefined"

В предыдущих версиях vue-router вы бы: Vue.use(VueRouter), с 2.0 вы можете ввести маршрутизатор в приложение, как показано ниже:

const routes = [
  { path: '/foo', component: Foo },
]

const router = new VueRouter({
  routes
})

const app = new Vue({
  router // inject the router
}).$mount('#app')

это должно сделать его доступным как this.$router во всем приложении


После ответа на соответствующий вопрос: Как использовать Vue Router из состояния Vuex? кажется, что Vuex не получит экземпляр маршрутизатора в this.$router. Поэтому было предложено два метода для обеспечения доступа к экземпляру маршрутизатора.

Первое более прямое, что связано с установкой глобального веб-пакета в экземпляр.

Вторым является использование Promises с вашим действием vuex, которое позволит вашим компонентам использовать их ссылку на экземпляр маршрутизатора после действий Promise, разрешающих/отклоняющих.

Ответ 3

Этот пример может помочь вам.

main.js

import Vue from "vue";
import VueRouter from "vue-router";

...

Vue.use(VueRouter);

export const router = new VueRouter({
    mode: 'hash',
    base: "./",
    routes: [
        { path: "/", component: welcome},
        { path: "/welcome", component: welcome},

    ]
})

actions.js

import {router} from "../main.js"

export const someAction = ({commit}) => {

    router.push("/welcome");
} 

Ответ 4

Мне не нравилось хранить состояние местоположения моего приложения отдельно от остальной части состояния моего приложения в Магазине и необходимость управлять как Маршрутизатором, так и Магазином, поэтому я создал модуль Vuex, который управляет состоянием местоположения внутри Магазина.

Теперь я могу перемещаться, отправляя действия, как и любое другое изменение состояния:

dispatch("router/push", {path: "/error"})

Это дает дополнительное преимущество, облегчая обработку таких вещей, как переходы анимированных страниц.

Нетрудно свернуть свой собственный модуль router, но вы также можете попробовать мой, если хотите:

https://github.com/geekytime/vuex-router

Ответ 5

НАЧАЛЬНЫЙ ОТВЕТ

В main.js (той, где мы "устанавливаем" все модули и создаем экземпляр Vue, т.е. src/main.js):

const vm = new Vue({
  el: '#app',
  router,
  store,
  apolloProvider,
  components: { App },
  template: '<App/>'
})

export { vm }

Это мой пример, но в нашем случае наиболее важными здесь являются const vm и router

В вашем store:

import { vm } from '@/main'

yourMutation (state, someRouteName) {
  vm.$router.push({name: someRouteName})
}

P.S. Используя import { vm } from '@/main', мы можем получить доступ ко всему, что нам нужно в Vuex, например, vm.$root, что необходимо некоторым компонентам bootstrap-vue.

P.P.S. Кажется, мы можем использовать vm только тогда, когда все загружено. Другими словами, мы не можем использовать vm внутри someMutation в случае, если мы вызываем someMutation внутри mounted(), потому что mounted() приходит/происходит до того, как будет создан vm.


НОВЫЙ ОТВЕТ

Константин ответ (принятый) лучше моего, поэтому просто хочу показать новичку, как его реализовать.

Внутри основной директории (внутри /src в моем случае), рядом с App.vue, main.js и другими, у меня есть router.js с содержанием:

import Vue from 'vue'
import Router from 'vue-router'

// Traditional loading
import Home from '@/components/pages/Home/TheHome'

// Lazy loading (lazy-loaded when the route is visited)
const Page404 = () => import(/* webpackChunkName: "Page404" */ '@/components/pages/404)
const Page503 = () => import(/* webpackChunkName: "Page503" */ '@/components/pages/503)

Vue.use(Router)

const router = new Router({
  mode: 'hash',
  base: process.env.BASE_URL,
  linkExactActiveClass: 'active',
  routes: [
    {
      path: '*',
      name: 'Page404',
      component: Page404
    },

    {
      path: '*',
      name: 'Page503',
      component: Page503
    },

    {
      path: '/',
      name: 'Home',
      component: Home
    },

    // Other routes
    {....},
    {....}
  ]
})

// Global place, if you need do anything before you enter to a new route.
router.beforeEach(async (to, from, next) => {
  next()
})

export default router

Импортируйте наш маршрутизатор в main.js:

import Vue from 'vue'
import App from './App.vue'
import router from './router'

Vue.config.productionTip = false

const vm = new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')

export { vm }

Наконец, внутри вашего компонента или Vuex или где-либо еще import router from './router' и делайте все, что вам нужно, например, router.push(...)