I don't understand how getters work in Vuex. The problem is when logging out the token in state and localStorage is becoming empty, but not in getters.
In created
I call this:
created: async function () {
if (this.$store.getters.shortToken) {
this.isConfirm = true
}
console.log(
'signining', localStorage.getItem('token'), // ''
'state', this.$store.state.user.token, // ''
'getter', this.$store.getters.token // 'old-token'
)
if (this.$store.getters.token) {
await this.$router.push({ path: '/' })
}
}
And getters
have:
token: state => {
return localStorage.getItem('token') || state.user.token
}
And mutation
:
SET_TOKEN: (state, payload) => {
localStorage.setItem('token', payload.token)
Object.assign(state, payload)
}
BUT, console log in created gives me empty localStorage token (which is normal) and empty state.token (which is also normal).. But, getters.token gives me token (which is NOT normal), because I gave SET_TOKEN empty token. Why is this happening?
PS. If I'm adding console.log(state.user.token, localStorage.getItem('token'))
above return
in getters token, so getters.token
in created
hook is empty... WHY?
Also some using codes in this situation, this is logout method:
methods: {
async logout () {
if (await this.$store.dispatch('logOut')) {
console.log('logged out')
await this.$router.push({ path: '/signin' })
}
}
}
action logout
async logOut (context) {
console.log('logggog')
context.commit('SET_TOKEN', {
token: ''
})
context.commit('SET_USER', {
user: null
})
return true
}
Getters are meant to compute derived state
based on store state
.
You are facing this problem because you are returning the value of localStorage.getItem()
from your Getter
, which is not a value of the store state
, thus it is not reactive
nor observable
.
In your example, Vuex will not recompute the value of the Getter when you call localStorage.setItem()
.
It will recompute the Getter's value only when state.user.token
is changed.
So, if you want to have the Getter working correctly, return just the value of state.user.token
.
You can also add a created
hook in your App.vue
that would check if there is a token in the localStorage and call the SET_TOKEN
mutation, if that is what you were trying to accomplish by calling localStorage.getItem
in your Getter:
App.vue
<script>
created() {
const token = localStorage.getItem('token');
if (token != null) {
this.$store.mutations.SET_TOKEN({ token });
}
}
</script>
Nonetheless, be aware of change detection caveats when using Object.assign
, because Vuex mutations follow Vue's reactivity rules.
In your mutation you should probably do:
SET_TOKEN: (state, payload) => {
localStorage.setItem('token', payload.token);
state.token = payload.token;
}
or if payload
is actually state.user
you can do:
SET_TOKEN: (state, payload) => {
localStorage.setItem('token', payload.token);
state.user = {
...payload
}
}