position payload in attribute for action? - vuex

Where I must type 'payload' in attributes for action?
In {} brackets or outside?
1 option:
async loadData( {state, payload, dispatch}) {
try {
...omitted
}
} catch (e) {
console.error(e)
}
},
2 option:
async loadData( {state,dispatch}, payload) {
try {
...omitted
}
} catch (e) {
console.error(e)
}
},

The first argument can be destructured to access a lot of useful things to access some state, run a quick mutation etc...more details here: https://vuex.vuejs.org/api/#actions
The second argument is the actual payload that you are passing if you want to update something with some data.
Not to confuse with a dispatch where you pass the name + payload directly.
So, option 2.

Related

vue computed not firing when vuex state changes

I dont know why, but my computed property is not firing when state changes.
I am dispatching actions and as a result state changes. but data is not firing at all. wanna help :(
//store
mutations: {
setStudyData(state, payload) {
state.studyData = [...payload];
},
},
actions: {
async postLogin({ state, commit, dispatch }, { userId, userPass }) {
try {
const res = await axios.post(`${url}/v1/api/user/auth/signin`, {
userId,
userPass,
});
await commit("setSeq", res.data.user_seq);
await commit("setToken", res.data.accessToken);
await dispatch("getStudyLi");
console.log(state.studyData); //i can see the state changes here
} catch {
console.log("error");
}
},
computed: {
data(){
console.log(this.datas) //not working
return this.$store.state.login.studyData
}
},
You don't have any this.datas property in the code shown.
It is also important how do use the computed. It runs the computed method only if there is some call of computed value. You can not expect method to be called if you do not use this.data property in your component.
U can just use mapState instead, if u not gonna process your studyData anymore and save your time writing this.$store.state.login.studyData
computed: {
...mapState([
"studyData",
"studyData2",
]),
}

How to set vue-i18n in a component's property reactively

I am trying to display some messages or errors depends on an async function result.
When a response's request doesn't include the message property I should use my own.
The problem is that when I use this.$t("message") inside the someMethod method the response.message (data) it isn't reactive. So it won't change after the locale change.
<v-alert v-if="response.error || response.message"
:type="response.error ? 'error' : 'info'">
{{response.error ? response.error : response.message}}
</v-alert>
export default {
data() {
return {
response: {
message: "",
error: ""
}
};
},
methods: {
async someMethod() {
const apiResponse = await sendRequestToAnApi();
if (apiResponse.message) {
this.response.message = apiResponse.message;
} else {
this.response.message = this.$t("translation")
}
}
}
}
I guess I should use computed property to make it work, but I don't have a clue how to mix response object with possible API response.
Any help will be appreciated
You could have your API return not only a message but also a code, where the message could be a textual string based on user locale settings, and the code a slug that will always be English, like users.added or project.created. You can store this code in response.code and create a computed property checking this code and returning the correct vue-i18n translation.
export default {
data() {
return {
response: {
code: "",
error: ""
}
};
},
methods: {
async someMethod() {
const apiResponse = await sendRequestToAnApi();
if (apiResponse.code) {
this.response.code = apiResponse.code;
} else {
this.response.code = null
}
}
},
computed: {
translatedMessage () {
if (this.response.code === 'users.added') {
return this.$t('translate')
}
return 'unknown code'
}
}
}
Of course you could also make this work with a textual string coming from the API, but personally I like working with a specific code that is independent from language settings.

Vuex action "not a function" inside Nuxt fetch

I have just introduced error handling to one of my Nuxt pages and apparently the action mapped and called inside fetch raises a not a function error. If the try/catch block isn't there it works as expected and there's no error at all.
Here is my component stripped to the essential parts:
export default {
name: 'ViewArticle',
async fetch ({ error }) {
try {
await this.fetchArticle({ articleSlug: this.articleSlug })
} catch (err) {
error({ statusCode: 404, message: 'May the force be with you' })
}
},
computed: {
...mapGetters({
article: 'article/single'
}),
articleSlug () {
return this.$route.params.articleSlug
}
},
methods: {
...mapActions({
fetchArticle: 'article/fetchOne'
})
}
}
I am assuming that somehow mapActions only gets executed later in the spiel, but can't figure out how to prevent the error. This way, basically every time I load the page it gets immediately redirected to the error page.
The error message I'm getting is the following. Obviously fetchArticle is a function, and unless it's inside the try/catch block, it works as expected.
this.fetchArticle is not a function 03:30:51
at Object.fetch (52.js:32:18)
at server.js:2881:39
at Array.map (<anonymous>)
at module.exports../.nuxt/server.js.__webpack_exports__.default (server.js:2864:51)
Fetch provides the context as argument.
fetch(context)
Inside the context we can find our store. Here you can take a look what context contains: https://nuxtjs.org/api/context
fetch(context) {
let store = context.store;
}
People like to destructure it
fetch({ store }) {}
Your code should look like this:
async fetch ({ error, store }) {
try {
await store.dispatch('article/fetchOne', { articleSlug: this.articleSlug })
} catch (err) {
error({ statusCode: 404, message: 'May the force be with you' })
}
},
Fetch gets executed on the server side, thats why you get is not an function error. Its undefined
... fetch is called on server-side...
Use async fetch({store})
async fetch ({ error, store }) {
try {
await store.dispatch( 'article/fetchOne' , { articleSlug: this.articleSlug })
} catch (err) {
error({ statusCode: 404, message: 'May the force be with you' })
}

Access component's this inside firebase promise reposonse

I've tried to bind it like it doesn't seem to make the trick :)
firebaseInstance.auth().fetchSignInMethodsForEmail(this.signUpData.email)
.then((response) => {
... all logic
}).bind(this)
...since it outputs the following error:
firebaseInstance.auth(...).fetchSignInMethodsForEmail(...).bind is not a function
Here is the component's logic, can someone please suggest a proper way to access this after firebase response resolves? :bowing:
import { VALIDATION_MESSAGES, VALUES } from './signup.module.config'
import GLOBAL_EVENTS from 'values/events'
import { firebaseInstance } from 'database'
export default {
name: `SignUpForm`,
data() {
return {
signUpData: {
email: ``,
password: ``,
confirmPassword: ``
}
}
},
methods: {
onEmailSignUp() {
// Here this is component
console.log(this.$refs)
firebaseInstance.auth().fetchSignInMethodsForEmail(this.signUpData.email)
.then((response) => {
// other logic
} else {
// Here this is lost and equals undefined
this.$refs.email.setCustomValidity(`error`)
}
})
}
}
}
The bind instruction should be used on a function object, not on a function return value.
By doing
firebaseInstance.auth().fetchSignInMethodsForEmail(this.signUpData.email)
.then((response) => {
... all logic
}).bind(this)
You try to use bind on the return of the then method of you promise, which is a promise object and can't use bind.
You can try firebaseInstance.auth().fetchSignInMethodsForEmail(this.signUpData.email)
.then(function(response){
... all logic
}.bind(this))
instead. Here the bind is put on the function send in the promise so it should work correctly. I also transformed the function from arrow function to normal, because I think there is no need for arrow function with bind.
Using ES8 async/await sugar syntax you can do it like this :
async onEmailSignUp () {
try {
const response = await firebaseInstance.auth().fetchSignInMethodsForEmail(this.signUpData.email)
// other logic
} catch (error) {
console.log(error)
this.$refs.email.setCustomValidity(`error`)
}
}

Is there a way to use promise in action with this structure Vuex

I have an action which fires on form submit in component
this.$store.dispatch('registerAction', this.registerData);
Also in this component I want to show message like "Registration is successful".
For that I want to listen for property in my this.$store.state registerSuccess which is false by default.
registerAction (Vuex)
return this.api.registerUser()
.then(response => {
if(response.success) {
return store.dispatch('registerSuccess');
}
return store.dispatch('registerFail');
});
registerSuccess mutation sets state.registerSuccess = true; (and fail sets it to false)
Question:
How can I listen for changes to state.registerSuccess in this case? If I'm putting it in computed it returns false. Although it does change in Vuex store to true
computed: {
registerSuccess() {
console.log(this.$store.state.registerSuccess)
return this.$store.state.registerSuccess;
}
},
You've mentioned that registerSuccess is a mutation which also means that you have put it inside the mutation property inside your store object like this:
{
state: {
registerSuccess: false
},
mutations: {
registerSuccess(state) {
state.registerSuccess = true;
}
}
}
In that case, you would need to use commit() to execute the registerSuccess mutation.
Your code should be:
return this.api.registerUser()
.then(response => {
if(response.success) {
return store.commit('registerSuccess');
}
return store.commit('registerFail');
});