0

When I login using a form this happens:

  1. loggedIn value in localStorage is changed to "true"
  2. Router pushes to /home
  3. Header doesn't change and still shows Login/Signup buttons

I need it to be

  1. loggedIn value in localStorage is changed to "true"
  2. Router pushes to /home
  3. Header changes and a picture

Header.vue:

      <div class="flex flex-wrap items-center justify-end ">
        <HeaderItem v-if="!isLoggedIn"
            class="pl-10" text = "Login" link="/login"/>
        <HeaderItem v-if="!isLoggedIn" class="pl-10"
                    text = "Signup" link="/signup"/>

        <div v-if="isLoggedIn">
          <UserHeader/>
        </div>
      </div>

export default {
  name: 'App',
  components: {HeaderItem, UserHeader},
  data() {
    return {
      homeLink: "/home"
    }
  },
  created: {
    isLoggedIn() {
      console.log(JSON.parse(localStorage.getItem("loggedIn")) === "true");

      if (localStorage.getItem("loggedIn") === "true")  {
        console.log("STORAGE LOGGED IN TRUE");
      }
      else  {
        console.log("STORAGE LOGGED IN FALSE");
      }

      return localStorage.getItem("loggedIn") === "true";
    }
  }
}

It only prints the correct message and changes header after I press Ctrl+Shift+R. But the localStorage has the correct loggedIn value right away. How do I fix it?

EDIT:

I also tried this:

  <div class="flex flex-wrap items-center justify-end ">
        <HeaderItem v-if="!loggedIn"
            class="pl-10" text = "Login" link="/login"/>
        <HeaderItem v-if="!loggedIn" class="pl-10"
                    text = "Signup" link="/signup"/>

        <div v-if="loggedIn">
          <UserHeader/>
        </div>
      </div>

export default {
  name: 'App',
  components: {HeaderItem, UserHeader},
  data() {
    return {
      homeLink: "/home",
     // loggedIn: false
    }
  },
  computed: {
    loggedIn() {
      return localStorage.getItem("loggedIn") === "true";
    },
...

It has the same results: the header only changes after the page refresh (Ctrl+Shift+R).

parsecer
  • 4,758
  • 13
  • 71
  • 140
  • Could you share where are you setting the localStorage loggedIn item and in sub component or parent component where are you checking isLoggedIn? – Riyaz Khan Apr 23 '21 at 20:13

1 Answers1

3

The created is a lifecycle or hook of vue.js, inside it whatever functions/methods you define, is not available to run.

As in your case, you want to use as a variable, then use computed property.

Here is the fix version of your code:

computed: {
      isLoggedIn() {
        console.log(JSON.parse(localStorage.getItem("loggedIn")) === "true");

        if (localStorage.getItem("loggedIn") === "true")  {
          console.log("STORAGE LOGGED IN TRUE");
        }
        else  {
          console.log("STORAGE LOGGED IN FALSE");
        }

        return localStorage.getItem("loggedIn") === "true";
      }
    },

Updated:

If you want your functions to be reactive on the same component, then create a variable and set its value where you set the localStorage loggedIn value.

This is just an example code:

<template>
  <div class="flex flex-wrap items-center justify-end ">
    <h3>{{ isLoggedIn }}</h3>
  </div>
</template>

<script>
  export default {
    data () {
      return {
        loggedIn: false
      }
    },
    created () {
      // added 3 seconds gap to make the value true and check reactivity
      setTimeout(() => this.onSignIn(), 3000)
    },
    computed: {
      
      isLoggedIn() {
        if (localStorage.getItem('loggedIn')) return localStorage.getItem("loggedIn") === "true";
        return this.loggedIn
      }
    },
    methods: {
      onSignIn () {
        this.loggedIn = true
        localStorage.setItem('loggedIn', true)
      }
    }
  }
</script>

Update 2 as per your situation:

After understanding your situation, here is the code, that will help you. I used the Bus Event in order to communicate between the component which might be far on the parent to access, such as App.vue.

event-bus.js

import Vue from 'vue';
const EventBus = new Vue();
export default EventBus;

LoginForm.vue

<template>
  <div class="home-page">
    <button type="submit" @click="onSignIn()">Login</button>
  </div>
</template>

<script>
import EventBus from '../event-bus';
  export default {
    methods: {
      onSignIn () {
        localStorage.setItem('loggedIn', true)
        EventBus.$emit('OnLogin', true)
      }
    }
  }
</script>

App.vue

<template>
  <div id="app">
    <Header :userLoggedIn="isLoggedIn"/>
    <router-view/>
  </div>
</template>
<script>
import Header from './components/Header'
import EventBus from './event-bus';
export default {
  components: {
    Header
  },
  data() {
    return {
      isLoggedIn: false
    }
  },
  created () {
    EventBus.$on('OnLogin', (isLogin) => {
      this.isLoggedIn = isLogin
    })
  }
}
</script>

Header.vue

<template>
  <div>
    <h2>{{ userLoggedIn }}</h2>
  </div>
</template>

<script>
  export default {
    props: ['userLoggedIn']
  }
</script>
Riyaz Khan
  • 2,765
  • 2
  • 15
  • 29
  • The issue is also compounded by the fact that `localStorage` objects are not reactive. – Ohgodwhy Apr 23 '21 at 19:38
  • @parsecer if you want it to be reactive on that same component, `create one variable` into `data` and update that...and for other pages, use the` localStorage` variable. – Riyaz Khan Apr 23 '21 at 19:41
  • @parsecer once you refresh the page, the above code will work, but without refreshing the page if you want, then you'll need one variable to use for checking this thing. – Riyaz Khan Apr 23 '21 at 19:43
  • `create one variable into data and update that...and for other pages, use the` localStorage` variable' could you show the code please? – parsecer Apr 23 '21 at 19:44
  • @RiyazKhan I need the header to get changed right away. So when the router pishes to /home the page there would have the updated header.. – parsecer Apr 23 '21 at 19:45
  • @parsecer do one thing, use the computed property, check the above code. And note, this is not reactive until you refresh the page. – Riyaz Khan Apr 23 '21 at 19:46
  • @RiyazKhan I **need** it to be **reactive**. That's the point of the question – parsecer Apr 23 '21 at 19:47
  • @parsecer one question, your header and `loggedIn localStorage` setup on the same component? – Riyaz Khan Apr 23 '21 at 19:47
  • What do you mean? Header uses `loggedIn` in `localStorage`. Login form changes `loggedIn` in `localStorage` – parsecer Apr 23 '21 at 19:49
  • @parsecer I had made the mistake, by putting signIn method inside computed, other than that, all are fines. now it's fixed. – Riyaz Khan Apr 23 '21 at 20:03
  • I can't use `onSignIn` method. My login form component is **independent** from Header. I **can't** **edit** `loggedIn` in `computed` (unexpected side effects error, see post EDIT). I can **only** take `loggedIn` value from `localStorage` – parsecer Apr 23 '21 at 20:10
  • @parsecer, why are you setting loggedIn variable into computed. it should be set where you are setting localStorage variable. – Riyaz Khan Apr 23 '21 at 20:15
  • @RiyazKhan I'm not sure what you mean. I think my question is pretty clear... I added some more code that I've tried – parsecer Apr 23 '21 at 20:19
  • @parsecer brother, the place where you set `localStorage.setItem('loggedIn')`, it's there you need to set your variable 'loggedIn' to make it reactive and pass it as props to sub component `Headers.vue` – Riyaz Khan Apr 23 '21 at 20:22
  • I can't do that. `loggedIn` is changed in `LoginForm.vue` which **is not** a parent of **Header.vue** and therefore **can't** set **Header** props from inside **LoginForm**. The **only** place Header is created is **App.vue**. I tried doing `
    ` inside **App.vue** but got an error: `Cannot read property 'getItem' of undefined`
    – parsecer Apr 23 '21 at 20:27
  • Maybe someone else knows the answer. Thanks for the help – parsecer Apr 23 '21 at 20:27
  • @parsecer That's what I was wanted to know, about LoginForm and App.vue where your header exists. Based on this, I have edited my solution. check the section `update 2` – Riyaz Khan Apr 23 '21 at 20:50