0

I'm trying to create a simple reactive navigation based on if a user is authenticated or not. A login method on a login view sets a token in localstorage. If set, I want to display the logout button. I've tried computed, standard methods and props to no avail.

When I login, the navigation does not update. HOWEVER, if I refresh the page (reinitialize the app), it does show the logout button.

What exactly am I doing incorrectly?

I have been trying for hours to grasp the concept of Vue JS and am on the brink of quitting. What would have taken me minutes to do server side has taken me hours client side. WHERE IS THE REACTIVITY?

Nav.vue

  <template>
    <nav class="navbar navbar-expand-lg navbar-dark bg-primary">
      <a class="navbar-brand" href="#">App</a>
      <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarColor01" aria-controls="navbarColor01" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
      </button>
      <div class="collapse navbar-collapse" id="navbarColor01">
        <ul class="navbar-nav">
          <li class="nav-item active">
            <a class="nav-link" href="#">
              <router-link to="/">Home</router-link>
              <span class="sr-only">(current)</span>
            </a>
          </li>
          <li class="nav-item">
              <router-link to="/about" class="nav-link">About</router-link>
          </li>
        </ul>
        <ul class="navbar-nav ml-auto">
          <li class="nav-item" v-if="hasAuth()"><a @click="logout()" class="nav-link">Log Out</a></li>
          <template v-else> 
            <li class="nav-item">
              <router-link to="/register" class="nav-link">Register</router-link>
            </li>
            <li class="nav-item">
              <router-link to="/login" class="nav-link">Login</router-link>
            </li>
          </template>
        </ul>
      </div>
    </nav>
  </template>

  <script>
  export default {
    name: 'Nav',
    data: () => {
      return {
        auth: false
      }
    },
    methods: {
      logout: function () {
        localStorage.removeItem('user-token');
        this.$router.push({ path: 'login' });
      },
      hasAuth: function () {
        this.auth = (localStorage.getItem('user-token')) ? true : false;
        return this.auth
      }
    },
  };
  </script>

App.vue

<template>
  <div id="app">
    <Nav></Nav>
    <router-view/>
  </div>
</template>

<script>
import Nav from '@/components/Nav.vue';

export default {
  components: {
    Nav,
  },
}
</script>
2
  • You can use different approaches here, but vuex would be perfect fit for this. You would add hasAuth to the store, and when user logs in, you commit the change. You can check this simple vuex example. Commented Jan 20, 2019 at 3:15
  • To use the reactivity, vue needs to be able to detect changes in your data. When you are saving / loading from localStorage, vue can't detect changes, and it won't update the template (no reactivity) Commented Jan 20, 2019 at 3:18

1 Answer 1

2

While Vue.js is reactive, localStorage is not. Vue cannot possibly know if the localStorage is modified or not. There is no local change event available with local storage.

To solve this problem, use Vuex combined with Local Storage for persistent data. The point where you save the token to local storage, at that time also save a copy inside Vuex store.

Another component like Nav should read data from Vuex store which is reactive. When you refresh the page, initialize Vuex store with the data from localStorage.

This way you get a perfect reactive system.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.