Vuex action cannot commit mutation - vue.js

I am working on an authentication function for a website, i am doing this with Firebase. Whenever the user logs into firebase my action in my store gets triggered and commits my mutation so the state gets set with the userID. Somehow whenever i try to commit my mutation i keep getting the error: commit is not defined. I can't seem to find a solution to this problem, all the forums i have been on havent helped so i really hope someone on here can help me with my problem, i would really appreciate it.
My action:
async login({ dispatch }, user) {
const token = await auth.currentUser.getIdToken(true);
const idTokenResult = await auth.currentUser.getIdTokenResult();
let approved = false;
const userData = await firestore.collection('users').doc(user.email).get();
if (userData) {
approved = userData.data().isApproved
}
const userInfo = {
name: user.displayname || null,
email: user.email || null,
avatar: user.photoURL || null,
uid: user.uid,
approved
};
Cookies.set('access_token', token); // saving token in cookie for server rendering
commit('saveUID', userInfo.uid);
}
};
My mutation:
saveUID (state, uid) {
state.uid = uid;
},

The first parameter of the action is the context, which has functions like commit and dispatch. You extract (destructuring assignment) the dispatch by using { dispatch } as your parameter. You can use { dispatch, commit } to fix this and actually assign commit to a local variable.
destructuring assignment
async login({ dispatch, commit }, user) {
commit('your_mutation')
}
using context
async login(context, user) {
context.commit('your_mutation')
}

Related

Vuex state property does not update

I'm developing a simple social media at the moment. I have a problem. token state property doesn't update at all, even when there is a token item in the localStorage. Here is my unfinished project on Github. And here is the store where the token property is stored (path: resources/js/store/modules/middleware.js):
const state = {
user: {
loggedIn: false,
isSubscribed: false,
token: localStorage.getItem('token') || ''
},
}
const actions = {}
const mutations = {}
const getters = {
auth(state) {
return state.user
}
}
export default {
namespaced: false,
state,
actions,
mutations,
getters
}
At first I thought that the state just updates before token item appears. So I decided to print the token in the console after 10 seconds (path of the file below: resources/js/middleware/auth.js):
export default function ({ next, store }) {
if (!store.getters.auth.token) {
console.log(store.getters.auth.token);
setTimeout(() => {
console.log(store.getters.auth.token);
}, 10000)
return next('login')
}
return next()
}
But the token was still an empty string. Here is how the console looks:
If you need something else to understand my question, feel free to ask!

nativescript wait for request until vuex complete request

I have page Login.vue and I am using a strategy if the user already logged in then go to Home Component else stay same
My Code
mounted() {
this.checkAlreadyLoggedIn();
},
methods: {
async checkAlreadyLoggedIn() {
this.busy = true;
await this.$store.dispatch("attempt");
this.busy = false;
if (this.$store.getters.loggedIn) {
this.$navigateTo(Home, {
clearHistory: true
});
}
},
}
attempt action request to server and get users detail
but it seems it triggers this.$store.getters.loggedIn early
Thank you
In order to wait properly before checking the getter, and trigger the busy state, return the promise from the attempt action:
attempt({ state, commit }) {
return axios.post(...) // <-- Returning the promise manually
.then(response => {
// Commit change
})
},
Or with async / await:
async attempt({ state, commit }) { // <-- async keyword returns promise automatically
const response = await axios.post(...);
// Commit change
}
Here is a demo

Update a data in database using vuex

I'm struggling to implement an EDIT_DETAILS feature in vuex but I can implement this without using vuex but I prefer to use vuex because I am practicing my vuex skills.
Below snippets are the code that I am using to make my edit feature work.
this is in my profile.vue
editUser(id) {
this.id = id;
let details = {
id: this.id,
FULL_NAME: this.personDetails[0].FULL_NAME,
EMAIL: this.personDetails[0].EMAIL
};
//this will pass the details to my actions in vuex
this.editDetails(details);
}
personDetails, just retrieves the details of my user in my database.
id is the user number which is the primary key of my table in my backend.
below is the example json came from my database
this is my action in my vuex:
async editDetails({ commit }, payload) {
try {
const response = await axios.put("http:/localhost:9001/profile/edit/" + payload);
commit("EDIT_DETAILS", response.data);
} catch (err) {
console.log(err);
}
}
and this is my mutation:
EDIT_DETAILS(state, detail) {
state.details.findIndex((param) => param.id === detail);
let details = state.details
details.splice(details.indexOf(detail), 1)
state.details = details.body
}
and my state:
details: [],
Use a comma instead of plus in your axios request
Not sure what your response is but this does nothing
state.details.findIndex((param) => param.id === detail);
You need to push into array if not exists

How to pass info from inside of object inside a state

I am using Nuxtjs and I would like to take an id that is in my state and use it to make a new call to an API.
My carInfo has an IdAddress that I would like to use to call the API.
My store:
export const state = () => ({
allCars: [],
carInfo: [],
carAddress: []
});
export const actions = {
async fetchAll({ commit }) {
let cars= await this.$axios.$get(
"apiaddress"
);
commit("setCars", cars);
},
async fetchcar({ commit }, id) {
let car= await this.$axios.$get(
"apiaddress"
);
commit("setcar", car);
},
async fetchAddress({ commit }, id) {
let address = await this.$axios.$get(
"apiaddress"
);
commit("setAddress", address);
}
};
The Actions documentation says:
Action handlers receive a context object which exposes the same set of
methods/properties on the store instance, so you can call context.commit to
commit a mutation, or access the state and getters via context.state and
context.getters.
And it goes on to say that they often use argument destructuring which is why the parameter to actions often looks like this: { commit }.
In your case you could add state to the parameters and then you should be able to access your carInfo value from the state.
For example, change your fetchAll action to:
async fetchAll({ commit, state }) {
let cars = await this.$axios.$get(
apistate.carInfo.IdAddress
);
commit("setCars", cars);
},

Vuex, best practice with a global errors and notifications handling

here is what i do, and i'am not realy sure its correct :
//store
async addUser({commit}) {
try {
const {data} = await apiService.addUser()
commit('SET_USER', data)
commit('SET_NOTIFICATION', {type:'success', message: 'user successfuly created'})
} catch (error) {
commit('SET_NOTIFICATION', {type:'error', message:error})
}
}
SET_USER(state, user) {
state.users.push(user)
}
//my component:
async addUser() {
this.isLoading = true
await this.$store.dispatch('updatePatient', this.form)
this.isLoading = false
}
is it legit ?
sometimes i think i would need more logic inside my component depending on the succes or rejected api request. Should i put all the logic in my actions ? like i do at the moment ?
Maybe should I add a status state for each actions, for example :
state {
users: []
postUserSuccess: null
postUserError: false
updateUserSuccess: null
updateUserError: false
// ...
}
and do what i want in the component with a computed property mapped to the store ?
What do you think ?
I don't know if it's a best practice but I let the components the exception handling. That method has its pros (you don't have to pollute the state with error management) and cons (you have to repeat the error management code for every action call).
All service calls will be made in actions
The state will only be set in mutations.
All service calls will return a promise with a resolve(data to load in the state) and a reject(message errors to present).
There will be an interceptor to reject the response in case there's a custom error (here you can put if the response has an error prop reject the response and send as an error the error prop, now you don't have to deconstruct the response in the action).
I'm going to give you a simplified example (I use axios, you can learn how to do it with the library that you use).
Actions in Vuex are asynchronous. So you don't need to try/catch them.
ApiService - Add User
const addUser = () => {
return new Promise((resolve, reject) => {
axios
.post(url, user)
.then(response => resolve(response.data))
.catch(error => reject(error));
});
};
store
async addUser({commit}) {
const data = await apiService.addUser();
commit('SET_USER', data);
return data;
}
if the promise in apiService.addUser is resolved the commit is going to be made if is rejected axios will return the promise and you can catch the error in the component that calls the action.
Component
async addUser() {
this.isLoading = true;
try {
await this.$store.dispatch('updatePatient', this.form);
} catch (error) {
// here goes the code to display the error or do x if there is an error,
// sometimes I store an errors array in the data of the component other times I do x logic
}
this.isLoading = false;
}
State
Your state will be cleaner now that you don't need to store those errors there.
state {
users: []
}