web-dev-qa-db-fra.com

Accès à l'état Vuex lors de la définition des itinéraires Vue-Router

J'ai le magasin Vuex suivant (main.js):

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

//init store
const store = new Vuex.Store({
    state: {
        globalError: '',
        user: {
            authenticated: false
        }
     },
     mutations: {
         setGlobalError (state, error) {
             state.globalError = error
         }
     }
})

//init app
const app = new Vue({
    router: Router,
    store,
    template: '<app></app>',
    components: { App }
}).$mount('#app')

J'ai également les itinéraires suivants définis pour Vue-Router (routes.js):

import Vue from 'vue'
import VueRouter from 'vue-router'

Vue.use(VueRouter)

//define routes
const routes = [
    { path: '/home', name: 'Home', component: Home },
    { path: '/login', name: 'Login', component: Login },
    { path: '/secret', name: 'Secret', component: SecretPage, meta: { requiresLogin: true }
]

J'essaie de faire en sorte que si l'objet user du magasin Vuex ait la propriété authenticated false, le routeur redirige l'utilisateur vers la page de connexion.

J'ai ceci:

Router.beforeEach((to, from, next) => {
    if (to.matched.some(record => record.meta.requiresLogin) && ???) {
        // set Vuex state's globalError, then redirect
        next("/Login")
    } else {
        next()
    }
})

Le problème est que je ne sais pas comment accéder à l'objet user du magasin Vuex depuis l'intérieur de la fonction beforeEach.

Je sais que je peux avoir la logique de garde du routeur dans les composants en utilisant BeforeRouteEnter, mais cela encombrerait chaque composant. Je veux plutôt le définir de manière centralisée au niveau du routeur.

15
Ege Ersoz

Comme suggéré ici , vous pouvez exporter votre magasin à partir du fichier dans lequel il se trouve et l'importer dans routes.js. Ce sera quelque chose comme suit:

Vous avez un store.js:

import Vuex from 'vuex'

//init store
const store = new Vuex.Store({
    state: {
        globalError: '',
        user: {
            authenticated: false
        }
     },
     mutations: {
         setGlobalError (state, error) {
             state.globalError = error
         }
     }
})

export default store

Maintenant, dans routes.js, vous pouvez avoir:

import Vue from 'vue'
import VueRouter from 'vue-router'
import store from ./store.js

Vue.use(VueRouter)

//define routes
const routes = [
    { path: '/home', name: 'Home', component: Home },
    { path: '/login', name: 'Login', component: Login },
    { path: '/secret', name: 'Secret', component: SecretPage, meta: { requiresLogin: true }
]

Router.beforeEach((to, from, next) => {
    if (to.matched.some(record => record.meta.requiresLogin) && ???) {
        // You can use store variable here to access globalError or commit mutation 
        next("/Login")
    } else {
        next()
    }
})

Dans main.js, vous pouvez également importer store:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

import store from './store.js'

//init app
const app = new Vue({
    router: Router,
    store,
    template: '<app></app>',
    components: { App }
}).$mount('#app')
20
Saurabh

J'ai fini par déplacer le magasin hors de main.js et dans store/index.js, puis à l'importer dans le fichier router.js:

import store from './store'

//routes

const routes = [
    { path: '/home', name: 'Home', component: Home },
    { path: '/login', name: 'Login', component: Login },
    { path: '/secret', name: 'Secret', component: SecretPage, meta: { requiresLogin: true }
]    

//guard clause
Router.beforeEach((to, from, next) => {
    if (to.matched.some(record => record.meta.requiresLogin) && store.state.user.authenticated == false) {
        store.commit("setGlobalError", "You need to log in before you can perform this action.")
        next("/Login")
    } else {
        next()
    }
})
1
Ege Ersoz

Si vous gérez votre état de localisation séparément du reste de votre état d'application, cela peut rendre les choses comme cela plus difficiles qu'elles ne le devraient peut-être. Après avoir traité des problèmes similaires dans Redux et Vuex, j'ai commencé à gérer mon état de localisation dans mon magasin Vuex, à l'aide d'un module router. Vous voudrez peut-être penser à utiliser cette approche.

Dans votre cas spécifique, vous pouvez surveiller le moment où l'emplacement change dans le magasin Vuex et envoyer l'action de "redirection" appropriée, comme ceci:

dispatch("router/Push", {path: "/login"})

Il est plus facile que vous ne le pensez de gérer l'état de l'emplacement en tant que module Vuex. Vous pouvez utiliser le mien comme point de départ si vous voulez l'essayer: 

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

1
Chris Jaynes

C'est comme ça que je le ferais.

Dans App.vue, je garderai un observateur sur un cookie qui stockera les détails d'authentification. (Évidemment, je stockerais un jeton contenant les détails de l'authentification en tant que cookie après l'authentification)

Maintenant, chaque fois que ce cookie devient vide, je dirigerai l'utilisateur vers la page de connexion. La déconnexion supprime le cookie. Maintenant, si l'utilisateur répond après la déconnexion, puisque le cookie n'existe pas (ce qui nécessite que l'utilisateur soit connecté), l'utilisateur sera routé vers la page de connexion.

0
chirag jain