How to access vuex getters from vue-router and set guards?
Asked Answered
I

2

8

I am trying to get into the way of things with Vue but I've got some troubles with:

1: I cannot get access to my getters from router/index.js file. (I can get access to it but it return like a function with returns function with I cannot call and get the value)

2: I cannot set up guard properly. With Angular it's much easier

What am I doing wrong here? Any suggestions?

Router code

/* eslint-disable no-undef */
import Vue from "vue";
import VueRouter from "vue-router";
// import auth from '../store/modules/auth';
import { createNamespacedHelpers } from "vuex";
const { mapGetters } = createNamespacedHelpers("auth");
// import store from '../store';


Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    name: "Home",
    component: () => import("../components/Home.vue"),
    meta: { requiresAuth: true }
  },
  {
    path: "/users",
    name: "Users",
    component: () => import("../components/Users/Users.vue"),
    meta: { requiresAuth: true }
  },
  {
    path: "/sign-in",
    name: "SignIn",
    component: () => import("../components/SignIn/SignIn.vue"),
  }
];

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes
});

router.beforeEach((to, from, next) => {
  const storeGetters = { ...mapGetters(['isAuthenticated', 'authStatus', 'test']) };

  const isUserLoggedIn = storeGetters.isAuthenticated;

  if (to.matched.some(record => record.meta.requiresAuth)) {
    if (isUserLoggedIn) {
      console.log('user is authenticated');
      to; from;
      return next();
    } else {
      console.log('Access denied!');
      next({
        path: '/signIn',
        query: { redirect: to.fullPath }
      });
    }

    next({
      path: '/signIn',
      query: { redirect: to.fullPath }
    });

  } else {
    next();
  }

})

export default router;

Vuex index

import Vue from "vue";
import Vuex from "vuex";
import modules from "./modules"

Vue.use(Vuex);

export default new Vuex.Store({
  strict: true,
  modules,
  state: {
    testState: 'State value'
  },
  getters: {
    test: state => state
  }
});

auth module (vuex)

import { apolloClient } from '@/vue-apollo';
import SignInGQL from "@/graphql/signIn.gql";

export default {
    namespaced: true,
    state: {
        token: null,
        authStatus: false
    },
    getters: {
        isAuthenticated: (state) => {
            console.log('state: ', state);
            return !!state.token;
        },
        authStatus: state => state.authStatus,
        test: state => state.authStatus
    },
    actions: {
        async signIn({ commit, dispatch }, formInput) {

            try {
                const { data } = await apolloClient.mutate({
                    mutation: SignInGQL,
                    variables: { ...formInput }
                })

                const { token } = data.signIn;
                await commit('setToken', token);
                localStorage.setItem('auth-token', token);
                await dispatch('setUser', token);
            } catch (e) {
                console.error(e)
            }
        },
        async setUser({ commit }, token) {
            const encodedPayload = token.split('.')[1];

            const { payload } = JSON.parse(atob(encodedPayload));

            // TODO: Set User information 
            await commit('signInUser', payload);
        }
    },
    mutations: {
        setToken(state, token) {
            state.token = token
        },
        signInUser(state, user) {
            console.log('authStatus: ', state.authStatus)
            state.authStatus = true
            state.user = { ...user }
            console.log('authStatus: ', state.authStatus)
        },
        logOutUser(state) {
            console.log('dispatched logOutUser')
            state.authStatus = ''
            state.token = '' && localStorage.removeItem('auth-token')
        }
    }
}
Idona answered 19/4, 2020 at 10:16 Comment(0)
Q
9

It seems createNamespacedHelpers is just complicating things. Import the store:

import store from '@/store'; // <-- aliased path

Use the getters like this:

const isAuthenticated = store.getters['auth/isAuthenticated'];
const authStatus = store.getters['auth/authStatus'];
const test = store.getters['auth/test'];

The first portion of the string is the Vuex module name, followed by the getter name.

Not only is this simpler to use, it's more readable and clear which module the getter comes from when studying the code.

Quiberon answered 20/4, 2020 at 7:24 Comment(5)
Thanks a lot to you for your help. I already thought I won't get any help here. Either here is no Vue community or this framework is not used at all. I tried your way and it seem to have worked quite well for me. I finally can get the result but not the function itself what gave me true all the time as any other truly value. I would appreciate if it won't bother you if I sometimes ask some questions on Vue because I have just started to learn it but apparently documentation, where I was looking for the answer and which gives "createNamespacedHelpers" as a solution doesn't help much.Idona
You're welcome, glad it helped. There's a fairly big Vue community here on SO I think, but createNamespacedHelpers is not often used, and seems to be very troublesome with getters from my testing.Quiberon
what can you say about Vue? Is it a decent front end framework? I don't really like React and wanted to have an alternative to Angular and which is close and as fast as ReactIdona
Vue is easily the best framework in my opinion. The cleanest and the easiest.Quiberon
as you can see there are a lot of pitfalls with them. But that's what I could find on the documentation. Thanks again! A lot!Idona
E
1

I faced the same problem...

Every time I tried to retrieve the getter's data inside the router it returned the function itself instead of the desired function's return value.

The solution:

In my code I used to call the createStore method inside the main.js file, but in order to be able to call the store's getters inside the vue-router you need to refactor your code, calling createStore in the same index.js file you declared it:

Before refactoring:

main.js file...

import store from './modules/index.js'
import { createStore } from 'vuex';
const mainStore = createStore(store)
app.use(store)

index.js file (Vuex store)...

const store = { ... store code here ... }
export default store

After refactoring:

main.js file...

import store from './modules/index.js'
app.use(store)

index.js file (Vuex store)...

import { createStore } from 'vuex'; 
const store = createStore({ ... store code here ... })
export default store
Evangelical answered 12/7, 2022 at 13:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.