A cyclic dependency between 'router' and 'store' in Vuex app

Viewed 1941

I have a vue.js app with a router that prevents the pages from been open without authorization using the following code:

import Router from 'vue-router';
import store from '../store/index';

function guardAuth(to, from, next) {
  if (store.state.authorizationToken) {
    next();
  } else {
    next({
      name: 'login',
      query: { redirect: to.fullPath },
    });
  }
}

export default new Router({
  mode: 'history',
  routes: [
    {
      path: '/',
      name: 'toroot',
      redirect: 'login',
    },
    {
      path: '/overview',
      component: Overview,
      beforeEnter: guardAuth,
    },
    ....

and a store mutation that is called when an API call fails:

import axios from 'axios';
import Cookies from 'js-cookie';
import router from '../router/index';

export default new Vuex.Store({
state: {
mutations: {
  handleApiFail(state, err) {
    if (err && !axios.isCancel(err) && state.authorizationToken) {
      // Block subsequent logout calls.
      state.authorizationToken = null;
      // Clear the token cookie just in case.
      Cookies.set('authorizationToken', null);
      // Stop the current and subsequent requests.
      state.cancellationSource.cancel('Authorization token has expired.');
      router.push({ name: 'login', query: { expired: '1', redirect: window.location.pathname } });
    }
  },

as you can see from the code above 'router' imports 'store' and 'store' imports 'router' and as far as I see this causes 'store' to be undefined inside 'guardAuth()'. Obviously, I can get rid of this cyclic dependency by moving 'handleApiFail' to a separate '.js' file, but I am not sure that it is a good idea. Is there a better solution or some common approach for haling this sutiation? Should 'handleApiFail' be a mutation or a simple function? Can a mutation use 'router'? Do I really need to get rid of the cyclic dependency (for example, in C++ I does not)?

2 Answers

It be better handleapi fail in separate function than mutation. and if you want to check it before entering route. you could use beforeEnter() on your route.

check this docs about beforeEnter or another route properties

Store mutation methods should not perform any logic at all. Stores are only used to hold your global application state, they should not perform any logic like authorizing the user or navigating through your application. What you'll want to do is move the logic out of the store and into the component that does the authorization check. From there just do something like $store.commit('unauthorized') and $store.commit('authorized', user). Should look like this:

sendAuthRequest.then(
    (success) => {
        $store.commit('authorized', <userVariable>);
        $router.push(...);
    }, (failure) => {
        $store.commit('unauthorized');
        $router.push(...);
    }
);

Related