4

I an learning Vue (3) and vuex.

I have this store:

export default new Vuex.Store({
      state: {
        user: null
      },
    
      mutations: {
        setUserData (state, userData) {
          state.user = userData
          console.log('userData')
          console.log(userData)
          localStorage.setItem('user', JSON.stringify(userData))
          axios.defaults.headers.common.Authorization = `Bearer ${userData.access_token}`
        },
    
        clearUserData () {
          localStorage.removeItem('user')
          location.reload()
        }
      },
    
      actions: {
        login ({ commit }, credentials) {
          return axios
            .post('/login', credentials)
            .then(({ data }) => {
              commit('setUserData', data)
            })
        },
    
        logout ({ commit }) {
          commit('clearUserData')
        }
      },
    
      getters: {
        isLogged: state => !!state.user,
        user: state => state.user
      },

And in a component, I want to get the user connected like this:

<script>

import { mapGetters } from 'vuex'
export default {

  computed: {
    ...mapGetters({
      user: 'user'
    })
  },

  data () {
    return {
      stores: [],
      loading: false
    }
  },

  created () {
    console.log('toto')
    console.log(this.user.id)
    this.getStores()
  },

The first time the user logs in, it works fine: I can see the user.id in the console.

But when I refresh the page (and the user is connected), the user.id is undefined.

My question is: how to put the user in the store if the localstorage contains the user?

Dan
  • 59,490
  • 13
  • 101
  • 110
Dom
  • 2,984
  • 3
  • 34
  • 64

2 Answers2

12

You can load the initial state value directly from localStorage:

state: {
   user: JSON.parse(localStorage.getItem('user'))
},

Since you used JSON.stringify when setting, use JSON.parse when getting.

Dan
  • 59,490
  • 13
  • 101
  • 110
  • Does this then JSON parse the local storage from disk every single time you access the state? Or is that just the initial value? – partofthething Jul 21 '21 at 16:01
  • 1
    @partofthething - Just the initial value. If you want to change the storage, do it in the mutation that changes the state (or in an action that calls that mutation). – Dan Jul 21 '21 at 21:18
  • This does not work for me, it says 'localStorage is not defined' when i try to init the store state like you suggested. – Luckytechy Apr 04 '23 at 07:45
  • @Luckytechy It's part of the Window API so should always be defined. Maybe you're running the code on the server side. See this: https://stackoverflow.com/questions/52474208/react-localstorage-is-not-defined-error-showing – Dan Apr 04 '23 at 15:17
3

A more generic solution could be to use a plugin that persists the entire state to local storage, that way you don't have to deal with individual values and your whole application is still available when a user hits refresh:

https://www.npmjs.com/package/vuex-persist

If you want more granular control and at the same time the ability to store more complex data type than strings, have a look at localForage:

https://www.npmjs.com/package/localforage

Thomas Kuhlmann
  • 943
  • 7
  • 18
  • Why does the user data become undefined in the first place, isn't it supposed to persist across refresh. Is it a vuex thing ? – Yemi Kudaisi Nov 13 '21 at 14:06
  • 1
    @YemiKudaisi That's normal behaviour for browsers, when you close a tab the data is gone. The only way to prevent that is by storing the state locally and retrieving it when revisiting the same website again. Vuex maintains the state centrally in a session, so that when you go to different pages, you can still access it. But that just works while you are effectively still in the app, it doesn't help when you leave the app and come back. – Thomas Kuhlmann Nov 15 '21 at 10:47