【问题标题】:How to use Vue Router from Vuex state?如何从 Vuex 状态使用 Vue Router?
【发布时间】:2023-03-20 05:15:02
【问题描述】:

在我一直使用的组件中:

this.$router.push({ name: 'home', params: { id: this.searchText }});

改变路线。我现在已经将一个方法移动到我的 Vuex 操作中,当然 this.$router 不再有效。 Vue.router 也没有。那么,请问如何从 Vuex 状态调用路由器方法?

【问题讨论】:

标签: vue.js vue-router vuex


【解决方案1】:

我假设 vuex-router-sync 在这里没有帮助,因为您需要路由器实例。

因此,尽管这感觉不太理想,但您可以在 webpack 中将实例设置为全局,即

global.router = new VueRouter({
  routes
})

const app = new Vue({
  router
  ...

现在您应该能够:router.push({ name: 'home', params: { id: 1234 }}) 在您应用中的任何位置


作为替代方案,如果您不喜欢上述想法,您可以从您的操作中返回一个 Promise。然后,如果操作成功完成,我假设它会调用突变或其他东西,您可以resolve Promise。但是,如果它失败并且重定向需要的任何条件都会命中reject Promise。

通过这种方式,您可以将路由器重定向移动到一个组件中,该组件只需捕获被拒绝的 Promise 并触发 vue-router 推送,即

# vuex
actions: {
  foo: ({ commit }, payload) =>
    new Promise((resolve, reject) => {
      if (payload.title) {
        commit('updateTitle', payload.title)
        resolve()
      } else {
        reject()
      }
    })

# component
methods: {
  updateFoo () {
    this.$store.dispatch('foo', {})
      .then(response => { // success })
      .catch(response => {
        // fail
        this.$router.push({ name: 'home', params: { id: 1234 }})
      })

【讨论】:

  • 您的第一个建议有效 - 谢谢。为什么将路由器连接到全局是一个坏主意?同样,我需要对 Vue-Resource 进行全局访问——由于某种原因,导入 Vue 并使用 Vue.http 可以正常工作(但它是最优的吗?)无论我需要 Vue-Resource 的任何地方。我也应该将 Vue-Resource 附加到全局吗?关于您的第二点,我会调查一下(我不太了解承诺)
  • 我不太确定这是一个坏主意,只是感觉有点不对劲——像这样应该是 vuex-router-sync 内置的东西。我已经详细说明了第二个想法,以防万一,因为我真的很喜欢 Promises!关于 vue-resource 的观点,是的,这很好 - Vue.http 旨在以这种方式使用,无需将其设为全局。
  • 我的 Promise 语法有问题 - 你介意花点时间看看吗? jsbin.com/webezelaki/edit?js
【解决方案2】:

我发现自己使用.go 而不是.push

对不起,没有解释为什么,但在我的情况下它有效。我把它留给像我这样的未来 Google 员工。

【讨论】:

    【解决方案3】:

    我相信 rootState.router 将在您的操作中可用,假设您在主 Vue 构造函数中将 router 作为选项传递。

    正如 GuyC 所提到的,我还认为您最好从您的操作中返回一个承诺并在它解决后路由。简单来说:dispatch(YOUR_ACTION).then(router.push())

    【讨论】:

    • 是的,我最终还是采用了 GuyC 提到的 Promise 方法。您是如何学习的/我们期望如何了解 rootState?没有看到任何地方记录。
    • 是的,它可能没有在文档中得到应有的重视。它在 Vuex actions 文档中有所提及,否则仅在 modules 文档中提及 - 它绝对不会跳出来。
    • rootState 默认没有router。手动注入它也将是矫枉过正,因为路由器实例大多是不可变的,除了 route 本身,如果使用 vuex-router-sync,它是状态的一部分。
    【解决方案4】:
        state: {
            anyObj: {}, // Just filler
            _router: null // place holder for router ref
        },
        mutations: {
            /***
            * All stores that have this mutation will run it
            *
            *  You can call this in App mount, eg...
    
            *  mounted () {
            *    let vm = this
            *    vm.$store.commit('setRouter', vm.$router)
            *  }
            *
            setRouter (state, routerRef) {
                state._router = routerRef
            }
        },
        actions: {
            /***
            * You can then use the router like this
            * ---
            someAction ({ state }) {
                if (state._router) {
                    state._router.push('/somewhere_else')
                } else {
                    console.log('You forgot to set the router silly')
                }
            }
        }
    }
    
    

    【讨论】:

      【解决方案5】:

      更新

      在我发布此答案后,我注意到以我呈现 Typescript 的方式定义它停止检测state 的字段。我认为那是因为我使用了any 作为一种类型。我可能可以手动定义类型,但这听起来像是在重复我自己。就目前而言,我最终得到了一个函数而不是扩展一个类(如果有人知道的话,我很乐意让我知道其他解决方案)。

      import { Store } from 'vuex'
      import VueRouter from 'vue-router'
      // ...
      
      export default (router: VueRouter) => {
        return new Store({
        // router = Vue.observable(router) // You can either do that...
        super({
          state: {
            // router // ... or add `router` to `store` if You need it to be reactive.
            // ...
          },
          // ...
        })
      }
      
      import Vue from 'vue'
      import App from './App.vue'
      import createStore from './store'
      // ...
      
      new Vue({
        router,
        store: createStore(router),
        render: createElement => createElement(App)
      }).$mount('#app')
      

      初答内容

      我个人刚刚为典型的Store 类做了一个包装器。

      import { Store } from 'vuex'
      import VueRouter from 'vue-router'
      // ...
      
      export default class extends Store<any> {
        constructor (router: VueRouter) {
          // router = Vue.observable(router) // You can either do that...
          super({
            state: {
              // router // ... or add `router` to `store` if You need it to be reactive.
              // ...
            },
            // ...
          })
        }
      }
      

      如果您需要$route,您可以使用router.currentRoute。请记住,如果您希望 gettersrouter.currentRoute 按预期工作,您宁愿需要 router 反应式。

      在“main.ts”(或“.js”)中,我只是将它与new Store(router) 一起使用。

      import Vue from 'vue'
      import App from './App.vue'
      import Store from './store'
      // ...
      
      new Vue({
        router,
        store: new Store(router),
        render: createElement => createElement(App)
      }).$mount('#app')
      

      【讨论】:

        猜你喜欢
        • 2023-03-06
        • 2019-11-11
        • 2021-04-11
        • 1970-01-01
        • 2016-08-10
        • 2017-07-25
        • 2020-01-20
        • 2019-08-13
        • 2020-09-21
        相关资源
        最近更新 更多