From the book:
To invoke a mutation handler, you need to call store.commit with its type: store.commit('increment')
Mutations must always be synchronous.
From the book:
Actions commit mutations ( can be asynchronous )
Actions are triggered with the store.dispatch method: store.dispatch('increment')
So it's action -> mutation -> new state most of the time.
So what's confusing me, is the very simple example, whereby I'm trying to show the asynchronous result of an object getTest
See this pen
Why can't Vue see that I'm not calling a mutation, but an action when the component loads?
What is this "book" you are talking about? I'm asking because you are using a mix of new Vuex 2.* and old, Vuex 1.* syntax, which is not working anymore in 2.*, so I assume you are learning in part from outdated resources.
(Sidenote: Why are you using Vue 1? Vue2.* has been out for over 10 months now...)
Your action and mutation definitions are correct, but there's no vuex: {} key in components anymore in Vuex 2.*
Also, you are trying to dispatch an action 'INCREMENT', but oyour store only has a mutation by that name, no action. So you have to use commit rather than dispatch.
Instead, you directly add computed props and method to your instance, or use the map*helpers provided by Vuex:
var vm = new Vue({
el: '[vue=app]',
data: {
welcome: 'Testing Vuex'
},
store: myStore,
created() {
this.$store.dispatch(FETCH_TEST_STATE)
},
computed: {
...Vuex.mapState( {
count: state => state.count,
getTest: state => state.testState
}),
}
methods: {
increment({dispatch}) {
this.$store.commit('INCREMENT', 1)
}
}
})
the action you call from created doesn't work because async/await was acting up on codepen
the commit called from this action didn't set any state.
Fixing all of this, here's your working example:
https://codepen.io/LinusBorg/pen/NvRYYy?editors=1010
Related
How can I in user.js call mutation from whoToFollow.js called reset ? Is it even possible ? Heres my code:
async logOut({commit}) {
this.$cookies.remove('token');
commit('set_token', null);
commit('whoToFollow/reset');
this.$router.push('/sign-in');
},
But it doesn't work I get this error:
unknown local mutation type: whoToFollow/reset, global type: user/whoToFollow/reset
It is possible to call mutations from other stores directly. You are just missing the option '{root: true}', which is needed for namespaced modules.
I would recommend calling an action in the other store first though, which then again calls the mutations to stay true to the Vuex pattern. Actions -> Mutations
async logOut({commit, dispatch}) {
this.$cookies.remove('token');
commit('set_token', null);
// in the reset action you can then call the commit
dispatch('whoToFollow/reset', payloadHere, { root: true })
this.$router.push('/sign-in');
},
I advise you to check out the Vuex Api Documentation to learn more about this and why you will need 'root: true'.
https://vuex.vuejs.org/api/#vuex-store-instance-methods
this.$navigateTo works perfectly fine within the methods of my components, but inside a mutation neither of Vue.$navigateTo and this.$navigateTo work. My navigation depends on the result I get from an api call, if there is no way to perform a navigation from within store actions, how can I get some return value from an store action so I can perform my navigation within my component?
You can return a value from a store action. Since actions are async, you will need to handle the resulting promise, doing something like
store.dispatch('actionA').then((target) => {
// navigate to target
})
The concept is explained here:
https://vuex.vuejs.org/guide/actions.html#composing-actions
Here is How I solved it:
new Vue({
store,
render: h => h('frame', [h(store.state.is_logged_in ? App : Login)]),
created() {
this.$store.commit('setNav', t => this.$navigateTo(t));
if (this.$store.state.is_logged_in) {
this.$store.dispatch('init');
}
},
}).$start();
Now in my actions I do:
logout({commit, state}) {
console.log('logged out');
commit('log_out');
state.nav(Login);
},
Problem: Having started multiple long-polling streams that need to persist throughout the app lifecycle (regardless of the lifecycle of individual components), I'm looking for a way to unsubscribe in response to various events (e.g. route change, but not limited to). To that end I wrote the following code:
export const actions: ActionTree<TasksState, RootState> = {
async pollEventTasks({ dispatch, commit, state, rootState }, payload: any) {
const pollEventTasks$ = timer(0, 5000).pipe(
switchMap(_ => tasksService.loadTasksForEvent(payload.eventId)),
map((response: any) => {
commit('setTasks', response);
})
).subscribe();
// this won't work in strict mode. Hot observables ~can't~ shouldn't be written to store:
// commit('longPolling/eventTasksPollingStarted', pollEventTasks$, {root: true});
},
A hot observable "updates itself", thus mutating store outside of mutation handler. What would be a neat solution fitting vue/vuex best practices?
We ended up building a plugin injected via Vue.use and storing Observable subscriptions there
I'm pretty new to Vuex and am having difficulty understanding how to handle a state change from one module to another. Currently, I have a module called transactions which does an Ajax request and if successful it should close the Modal that is open. I have my modal state set in a separate module called General. I originally tried to set the General State of modal but committing my general mutation closeModal. I realized this won't work and as it sounds like Mutations aren't supposed to do this sort of heavy lifting. I've searched for another method to handle this sort of work and have been lead to Actions but I'm not clear on how to implement it or if it is even supposed to do this kind of work. Would someone please let me know if an Action is the correct method for this problem or if there is another way I should be addressing things.
I have a module called transactions that is running an ajax request and should close a modal if successful. For the sake of this issue, I've simplified my module.
const Transactions = {
state: {
},
mutations: {
CONFIRM_TRANSACTION_CANCEL: function(state) {
this.$store.commit('CLOSE_MODAL')
}
}
And I also have a second module called general which I want to use for general state management and error handling. I'm attempting to call a mutation from transactions into this general module.
const General = {
state: {
modalState: null,
},
mutations: {
...
CLOSE_MODAL: function(state) {
state.modalState = null
},
...
}
}
You should not make a commit inside a mutation. Mutations are only to change the state.
You could do this in two ways:
1.- Using Vue's Watch spying transaction state. Then, if the transaction is correctly done, you dispatch an action to close the Modal.
2.- You can dispatch an action to close the modal inside the action that launches the ajax call (after the success).
apiCall({ dispatch, commit }) {
api.get('/transaction')
.then((response) => {
dispatch('closeModal');
commit('TRANSACTION_SUCCESS', response);
})
.catch((error) => commit('TRANSACTION_ERROR', error));
}
These methods below are done with thinking of the modal as it should use vuex too but, if you want to simplify you can just:
3.- Pass the status of the transaction that comes from vuex directly to the modal by prop and handle the modal with it.
For anyone who has used VuexFire Vuex v2. What is mutations: VuexFire.mutations referring to here? The answer may be obvious but I have no idea what it means. Where do my actual mutations go then? I'm using Vuex v1 right now and it seems to be working fine but I would like to upgrade to using Vuex v2. Thanks!
var store = new Vuex.Store({
state: {
items: null
},
mutations: VuexFire.mutations, // What is this and where is it coming from??
getters: {
items: function (state) { return state.items }
}
})
new Vue({
el: '#app',
store: store,
computed: Vuex.mapGetters([
'items'
]),
firebase: {
items: db.ref('items')
}
})
I struggled with this one for a long while myself. Although I am not 100% sure of what the VuexFire.mutations does, I now understand that VuexFire is only in charge of getting your Firebase database data and correctly mutating your app state with that data.
So it seems that is the magical bit of code that make the local store's state mutation happen.
For your app to mutate / change Firebase database, you will still have to get the Firebase database reference and set / push / or whatever the data yourself.
For instance, using your code for illustration,
firebase: {
items: db.ref('items')
}
will let mutations: VuexFire.mutations 'know' what to mutate your app state with. But to mutate your Firebase database, you will have to do something like:
db.ref('items').push(WhateverNewData)
I hope this helps.