how to get the token of current user when logged in vuex - vue.js

i'm trying to show a component if a user is logged in vuex
this is my state
const state = {
status: "",
token: localStorage.getItem("token") || "",
user: {}
};
this is my getters
const getters = {
isLoggedIn: state => !!state.token,
authStatus: state => state.token
};
this is my response
state{
status:"success"
token:"eyJhbGciOiJIUzI1NiIsInR5c"
}
getters{
isLoggedIn:false
authStatus:undefined
}
i don't know why isLoggedIn:false when i'm getting the token

Related

Unable to store data in vuex "State"

I am unable to store the data from the API in the state, is there any issue in my code?
I am not able to console.log(state.token) or state.token from the mutations.
My Store
export const AUTH_MUTATIONS = {
SET_USER: 'SET_USER',
SET_PAYLOAD: 'SET_PAYLOAD',
LOGOUT: 'LOGOUT',
}
export const state = () => ({
token: null,
userdata: [],
data: [],
})
export const mutations = {
[AUTH_MUTATIONS.SET_USER] (state, { userdata }) {
state.userdata = userdata
},
[AUTH_MUTATIONS.SET_PAYLOAD] (state, { token }) {
state.token = token
},
}
export const actions = {
async login ({ commit, dispatch }, { email_id, password }) {
const { data: {data: { user, token } } } = await this.$axios.post('http://18.xxx.246.xxx:5000/api/v1/users/login',
{
email_id,
password
})
// console.log(user)
// console.log(token)
commit(AUTH_MUTATIONS.SET_USER, user)
commit(AUTH_MUTATIONS.SET_PAYLOAD, token)
// console.log(AUTH_MUTATIONS.SET_USER, user)
},
}
export const getters = {
isAuthenticated: (state) => {
return state.token && state.token !== ''
},
}
In your action you need to take in state in the destructured parameters like this: { commit, dispatch, state } then you will be able to access your state and log state.token.
If it's still null after that point then you should debug it to ensure that you're setting it correctly in the mutation itself.

Vue js Vuex unknown action type:

Please what am i doing wrong?
I have this codes on my login vue and main js pages but it returns the error above anytime i try to login.
Login.vue
this.$store.dispatch("settoken", token);
this.$store.dispatch("setuserid", userid);
this.$store.dispatch("setusertype", usertype);
this.$store.dispatch("setIsAuth", true);
main.js
const state = () => ({
user: null
});
const store = new Vuex.Store({
state,
getters: {
user: (state) => {
return state.user;
}
},
actions: {
user(context, user){
context.commit('settoken', user);
}
},
mutations: {
user(state, user){
state.user = user;
}
}
});

VueJS Axios: Getting JSON data

I'm trying to get this informations and put it in "user" :
the action in VueJS:
export default new Vuex.Store({
state: {
status: '',
token: localStorage.getItem('token') || '',
user : {},
test : []
},
mutations: {
auth_request(state){
state.status = 'loading'
},
auth_success(state, token, user){
state.status = 'success'
state.token = token
state.user = user
},
auth_error(state){
state.status = 'error'
},
logout(state){
state.status = ''
state.token = ''
},
},
actions: {
login({commit}, user){
return new Promise((resolve, reject) => {
commit('auth_request')
axios.get('http://localhost:8080/offreeduwar/api/Useraccount/login/'+ user.email+'/'+user.password)
.then((resp) => {
const token = resp.data.token
const user = resp.data
console.log(test)
localStorage.setItem('token', token)
// Add the following line:
axios.defaults.headers.common['Authorization'] = token
commit('auth_success', token, user)
resolve(resp)
})
.catch(err => {
commit('auth_error')
localStorage.removeItem('token')
reject(err)
})
})
},
But all the time in Vue devtool : the state of user is empty , so the question how to put this informations in user to work with this variable
The commit method in the store has two parameters: the name of the mutation and the params (if it is of a primitive type, the value itself, if it is an object, then an object). So you should try it like this:
commit('auth_success', { token, user })
and then:
auth_success(state, payload){
state.status = 'success'
state.token = payload.token
state.user = payload.user
},

Auto SignIn with Vuex and Vuex-persistedstate

I would like to auto-sign-in user when the page has been refreshed. I've read that I should use vuex-persistedstate to persist the token in localstorage. Here's my vuex store:
store: {
user: null
},
actions: {
autoSignIn ({commit}, payload) {
commit('setUser', { id: payload.token })
}
},
mutations: {
setUser (state, payload) {
state.user = payload;
}
},
plugins: [ createPersistedState({
getState: (key) => localStorage.getItem(key),
setState: (key, state) => localStorage.setItem('user_token', key)
}) ]
I also have signIn action where I create a newUser with token.
signUserIn ({commit, getters, state}, payload) {
let data = {
_username: payload.email,
_password: payload.password
}
Vue.http.post(
'url',
data,
{ channel: 'default' },
{ headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }
).then(response => {
const newUser = {
id: response.body.token
}
localStorage.setItem('user_token', response.body.token)
commit('setUser', newUser)
})
}
Then in main.js - created() I would like to check if the token is valid, afterwards - sign user in.
created() {
let token = localStorage.getItem('user_token')
if(token) {
this.$store.dispatch('autoSignIn', token)
}
}
The last part doesn't work, I know I should use getState, setState from createPersistedState but I have no idea how to do it. How do I make it work?
If the only use case for using vuex-persistedstate is to remember the access token then you should avoid using it in the first place and save yourself a few Kb from the final build file.
It would make more sense using it if you were to provide offline experience to your users.
If all you do is set state.user with the locally stored token then you could just do.
// if localStorage contains a serialized object with a 'token' attribute
const userToken = JSON.parse(window.localStorage.getItem('user_token'));
const state = {
user: userToken ? userToken.token || null : null
};
const mutations = {};
const actions = {};
export default {
state,
mutations,
actions,
}
Whenever you refresh the page and the store is being instantiated state.user will either take as default value the locally stored token or null if missing/undefined
However if i were you i would replace
const state = {
user: null
};
with
const state = {
accessToken: null
};
since all you store is the accessToken and not the user itself so its kind misleading.
update to answer the question in comments "... I need to check if the state has changed and use setUser mutation but don't how to achieve it."
There are 3 ways I can think of.
first of all change state to
const userToken = JSON.parse(window.localStorage.getItem('user_token'));
const state = {
accessToken: userToken ? userToken.token || null : null,
user: null,
};
then
The Simplest of all
on your App.vue component add a mounted method like the following
import { mapState, mapActions } from 'vuex';
export default {
...
computed: {
...mapState([
'accessToken',
'user',
])
},
mounted() {
if (this.accessToken && !this.user)
this.getAuthUser();
},
methods: {
...mapActions([
'getAuthUser',
]),
},
}
So on every refresh when the App is mounted and we have an accessToken but not a user we call getAuthUser() action which makes an ajax call and stores the received user with a setUser mutation
The Router Guard way
If you have a router and you only need to check for an authenticated user on certain routes then you can use route guards. for example
import store from '#/store';
export default new Router({
routes: [
...
{
path: '/admin',
component: Admin,
beforeEnter: (to, from, next) => {
if (!store.state.accessToken) return next('/login');
if (store.state.accessToken && !store.state.user) {
return store.dispatch('getAuthUser')
.then(() => {
// user was retrieved and stored and
// we can proceed
next();
})
.catch(() => {
// we couldn't fetch the user maybe because the token
// has expired.
// We clear the token
store.commit('accessToken', null);
// And go to login page
next('/login');
});
},
return next();
},
},
...
],
});
Using Vuex plugins
This is a method I've recently learned.
const storeModerator = (store, router) {
// listen to mutations
store.subscribe(({ type, payload }, state) => {
// if commit('setAccessToken') was called dispatch 'getAuthUser'
if (type === 'setAccessToken') {
store.dispatch('getAuthUser');
}
});
};
export default new Vuex.Store({
...,
plugins: [storeModerator]
});
You can learn more by checking:
Vue-router navigation guards
Vuex Plugins
Decouple Vuex modules with the Mediator pattern

Vue.js - Vuexx : state value undefined

After user login authentication ( LoginPage component ) the currentUserId is set in the store, but trying to get it later in another component ( ShoppingLists ) gives an undefined value ... what's wrong with my flow ?
here is my store.js
import Vue from 'vue'
import Vuex from 'vuex'
import getters from '#/vuex/getters'
import actions from '#/vuex/actions'
import mutations from '#/vuex/mutations'
import vueAuthInstance from '../services/auth.js'
Vue.use(Vuex)
const state = {
shoppinglists: [],
isAuthenticated: vueAuthInstance.isAuthenticated(),
currentUserId: ''
}
export default new Vuex.Store({
state,
mutations,
getters,
actions
})
Here are the console.log output with related pieces of code
// LoginPage component submit button fires the login action
methods: _.extend({}, mapActions(['login']), {
clearErrorMessage () {
this.hasError = false
},
submit () {
return this.login({user: { email: this.email, password: this.password }})
.then((logged) => {
if (logged) {
this.$router.push('shoppinglists')
} else {
this.hasError = true
}
})
}
}),
action.js
login: ({ commit }, payload) => {
payload = payload || {}
return vueAuthInstance.login(payload.user, payload.requestOptions)
.then((response) => {
// check response user or empty
if (JSON.stringify(response.data) !== '{}') {
commit(IS_AUTHENTICATED, { isAuthenticated: true })
commit(CURRENT_USER_ID, { currentUserId: response.data.id })
return true
} else {
commit(IS_AUTHENTICATED, { isAuthenticated: false })
commit(CURRENT_USER_ID, { currentUserId: '' })
return false
}
})
},
console.log
mutations.js?d9b0:23
state isAuthenticated: true
mutations.js?d9b0:27
committed state currentUserId: 1
At this point the store should be updated ....
// then the LoginPage component push the ShoppingListsPage
when mounted it shoudl populates the shoppinglists
methods: _.extend({}, mapActions(['populateShoppingLists', 'createShoppingList']), {
addShoppingList () {
let list = { title: 'New Shopping List', items: [] }
this.createShoppingList(list)
}
}),
store,
mounted: function () {
this.$nextTick(function () {
console.log('GOING TO POPULATE STORE SHOPPINGLISTS FOR CURRENT USER')
this.populateShoppingLists()
})
}
console.log
ShoppingListsPage.vue?88a1:52
GOING TO POPULATE STORE SHOPPINGLISTS FOR CURRENT USER
actions.js?a7ea:9
TRYING TO GET currentUserId with GETTERS
populateShoppingLists: ({ commit }) => {
console.log('TRYING TO GET currentUserId with GETTERS')
const currentUserId = getters.getCurrentUserId({ commit })
console.log('ACTIONS: populateShoppingLists for user: ', currentUserId)
return api.fetchShoppingLists(currentUserId)
.then(response => {
commit(POPULATE_SHOPPING_LISTS, response.data)
return response
})
.catch((error) => {
throw error
})
},
console.log
getters.js?d717:9
GETTERS: currentUserId: undefined
Getters returning an undefined value from the store
getCurrentUserId: (state) => {
console.log('GETTERS: currentUserId: ', state.currentUserId)
return state.currentUserId
},
UPDATE
mutations.js
import * as types from './mutation_types'
import getters from './getters'
import _ from 'underscore'
export default {
[types.POPULATE_SHOPPING_LISTS] (state, lists) {
state.shoppinglists = lists
},
[types.IS_AUTHENTICATED] (state, payload) {
console.log('committed state isAuthenticated: ', payload.isAuthenticated)
state.isAuthenticated = payload.isAuthenticated
},
[types.CURRENT_USER_ID] (state, payload) {
console.log('committed state currentUserId: ', payload.currentUserId)
state.currentUserId = payload.currentUserId
}
}
mutation_types
export const POPULATE_SHOPPING_LISTS = 'POPULATE_SHOPPING_LISTS'
export const IS_AUTHENTICATED = 'IS_AUTHENTICATED'
export const CURRENT_USER_ID = 'CURRENT_USER_ID'
I solved the issue , modifying the action populateShoppingLists
Need to pass the state as a parameter with the commit , so I can use the getters inside my action
populateShoppingLists: ({ commit, state }) => {
let currentUserId = getters.currentUserId(state)
console.log('currentUserId: ', currentUserId). // => userId: 1 Ok
return api.fetchShoppingLists(currentUserId)