2

I have setup a Vuex store and router in Vue. Depending on a piece of state within this store, I would like the router to render a different component for the same path. Below is my attempt at doing this.

Within my router, I include a conditional that is saying "if the user is logged in, return Home, otherwise return Login".

Within my Login component, I change the value of my loggedIn state (within the Vuex store) to true when the user successfully logs in. I have tested and can see this state is being updated, but the Home component is not being rendered upon this state change - it remains as Login.


Login.vue

<template>
  <div className = "container">
    <div className = "sign-in">
        <div className = "inner-sign-in">
            <div className = "title-outer">
                <div className = "title-inner">
                    <h1 className = "reg-title title">Tweeter</h1>
                    <span className = "slogan">Twitter, but not as good.</span>
                </div>
            </div>
            <div className = "form-outer">
                <form className = "sign-in-form" v-on:submit="submitForm">
                    <input @input="updateUsername" type="text" id="username" name="username" placeholder="Username" required/><br/>
                    <input @input="updatePassword" type="password" id="password" name="password" placeholder="Password" required/><br/>
                    <input type="submit" value="Login"/>
                    <div className = "wrongCreds">Sorry, incorrect username or password.</div>
                </form>
                <a className = "register-but" to="/register">Create an Account</a>
                <span className = "guestButton">Continue as Guest &gt;</span>
            </div>
        </div>
    </div>
  </div>
</template>

<script>
  import loginService from '../services/login.js'
  export default {
    name: 'Login',
    computed: {
      loggedIn() {
        return this.$store.getters.loggedIn
      }
    },
    methods: {
      updateUsername: function(event) {
        this.$store.commit('change', {
          name: "username",
          value: event.target.value
        })
      },
      updatePassword: function(event) {
        this.$store.commit('change', {
          name: "password",
          value: event.target.value
        })
      },
      async submitForm(e) {
        e.preventDefault()
        await loginService.login(this.$store.getters.username, this.$store.getters.password)
          .then(data => {
            console.log(data)
            this.$store.commit('change', {
              name: "loggedIn",
              value: true
            })
            console.log(this.$store.getters.loggedIn)
          })
          .catch(error => {
            console.log(error)
          })
      }
    }
  }
</script>

router.js

import { createRouter, createWebHistory } from 'vue-router'
import store from "../store/store"
import Home from "../Home.vue"
import Login from "../Login.vue"

const router = createRouter({
    history: createWebHistory(),
    routes: [
        { path: '/', component: function () {
            console.log(store.getters.loggedIn)
            if(store.getters.loggedIn) {
                return Home
            }
            else {
                return Login
            }
        }}
    ]
})

export default router

store.js

import { createStore } from 'vuex';

const store = createStore({
    state: {
        username: '',
        password: '',
        loggedIn: false
    },
    mutations: {
        change(state, theChange) {
            state[theChange.name] = theChange.value
        },
        arrayItemChange(state, theChange) {
            state[theChange.name][theChange.index] = theChange.value
        }
    },
    getters: {
        username: state => state.username,
        password: state => state.password,
        loggedIn: state => state.loggedIn
    }
})

export default store

3 Answers 3

1

The best practice and what you should do here is to use Navigation Guards.

Now, to speed you up, you need to set 2 navigation guards which checks if user is authenticated.

index.js (router file)

const ifNotAuthenticated = (to, from, next) => {
    if (!store.getters.loggedIn) {
        next();
        return;
    }
    next("/");
};

const ifAuthenticated = (to, from, next) => {
    if (store.getters.loggedIn) {
        next();
        return;
    }
    next("/login");
};

const routes =[
    {
        path: "/home",
        name: "Home",
        component: Home,
        beforeEnter: ifAuthenticated,
      },
    {
        path: "/login",
        name: "Login",
        component: Login,
        beforeEnter: ifNotAuthenticated,
      }
]

beforeEnter here is the key to know whether an authenticated user should proceed to the next page or go to login.

0

Configure the routes to simply have /home and /login (don't make logic there) and handle the login in your template or Vuex: router.push() to the correct path, to match your routes.

0

One of the ways to go about this is to have a parent component that houses Login and Home component, then use Dynamic component to toggle base on the state.

You can check Vue doc here

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.