Closed zipme closed 8 years ago
I think we had never implemented such feature... @yyx990803 Is this planning to implement?
Should we update the guide then?
Here is the code snippet taken from the guide:
cosnt moduleA = {
state: { count: 0 },
mutations: {
increment: (state, rootState) {
// state is the local module state
state.count++
// rootState is passed as the second argument, but you should not
// mutate it from within a module.
}
},
getters: {
doubleCount (state) {
return state.count * 2
}
}
}
But I do think this feature can be useful in some cases.
I am currently using vue-router
together with vuex-router-sync
, I would like to access the router
property of state
inside the mutation, but seems it's only available in rootState. So either we expose the rootState in the mutation, like in the doc, or we inject the router
into all modules' state. What do you think?
I think it is nice as an escape hatch but we should expose it as the 3rd argument because it would be hardly used in module mutations. In my opinion, we had better to use actions to access other modules state instead of in mutations.
yes, that makes sense, I will use action instead of mutation to access rootState. Thanks for the answer!
IMO, mutations should not have rootState.
An action is the intent of a mutation, and the mutation is the finalisation of that intent.
Therefore with that reasoning. Actions should be used to collate the data to commit to that the mutation.
@yyx990803 Would you agree?
@blake-newman Indeed this is a good reason to use actions instead of mutations, however, I am in a situation where changing the state should also update the url (by calling router.go
) what would be the best way to do this?
And a related question, I understand that the state should be the single source of truth, but so is the url. I often find myself syncing between url and the state, currently I am trying to change the url when the state is changed, should I maybe do this the other way around by updating the state in the activate
callback?
however, I am in a situation where changing the state should also update the url (by calling router.go) what would be the best way to do this?
- Import the router into the module where your action is
- call your mutation
- use
rootState
of the action to get the desired route information- use
route.go()
(orroute.push()
if using 2.0)I am trying to change the url when the state is changed, should I maybe do this the other way around by updating the state in the activate callback?
Probably.
/ping @yyx990803 What do you think about this? (the doc says module mutations will receive rootState their 2nd argument)
I spent an hour to figure out that it is an inconsistency with the API mentioned in the doc :/ wasn't able to get the payload
.
If i'm not mistaken, the purpose of modules is to allow encapsulation. I'm at a point in my app where my root store's mutations are beginning to be hard to manage and I don't even consider my app to be "mutation heavy" if we can say so. I could easily foresee cases way worst than mine. Those mutations are all committed from module actions but I can't afford to have the mutations be in their respective modules because a lot of my modules depend on the same state. :worried:
I could probably refactor my stores and sync the local module states with the root state somehow but I would still end up needing mutations in my root state to handle the bindings. Anybody came across an elegant solution?
Can we please reopen this? I need the rootState for some special cases.
If you can explain why having access rootState in actions is not enough for your special cases, we can talk about it.
In my case, I want to set track the user interaction with the webpage so i think mutations are the right place to keep track of that. I could put it on actions too, but i think that having it on mutations keep the code cleaner.
This way in the rootState i will have the tracker tool I use to call the remote apis , and in submodules i could do something like:
rootState.tracker.track('some event here')
I will give a try to put it on actions
In my case, I want to set track the user interaction with the webpage so i think mutations are the right place to keep track of that. I could put it on actions too, but i think that having it on mutations keep the code cleaner.
That sounds more like a perfect usecase for a plugin: https://vuex.vuejs.org/en/plugins.html
@LinusBorg I will take a look, thanks!
Ok so I think I have a scenario when rootState could be useful. So I have multiple collections and each collection has multiple videos. My store looks like this:
state: {
collections:[collectionOne:{
videos:[{videoOne: {
is_favourite: 0
}}]
}]
}
I think you get the idea, so inside my video component I fire an action in the video module:
favourite(context, data){
context.commit('setFavourite', data)
},
Then my mutation in the videos module is:
setFavourite({state, getters, rootState, rootGetters}, data) {
let videos = rootState.collections[ getKeyFromId(data.collectionId, rootState.collections) ]
videos[ getKeyFromId(data.id, videos) ].is_favourite = data.val;
},
Now the only way I can think of doing this at the moment is the video action fires a mutation in the Collections module but that kind of negates the point of having the modules.
Apologies if I missing something obvious, they're may be a way to do what i'm doing much better that I haven't thought of so open to suggestions.
I have a complex view with a complex model:
export default class RootClass extends BaseClass {
constructor(){
this.complexClass1 = new ComplexClass1()
this.complexClass2 = new ComplexClass2()
this.complexClass3 = new ComplexClass3()
this.complexClass4 = new ComplexClass4()
this.complexClass5 = new ComplexClass5()
//....30 some props, some functions, etc...
}
}
My vuex structure is something like this:
/store
/modules
class1.js
class2.js
class3.js
class4.js
index.js
What I want to do is query the api and load this complex model and store it in the root of vuex, and then be able to mutate that root state from the vuex submodules.
What I have to do now is call api, and commit the root class, commit to each vuex module (class 1, class 2, class 3, etc.) That is just for loading data. If I want to clear, I have to do the same.
Maybe I am doing this all wrong. I haven't come across any good examples for a large scale app.
Any update on this? Having the rootState is really helpful, but if that is not going to be implemented atleast mention a workaround.
The "workaround" (I would say: intended usage) is to repare the data in the action, which does have access to rootState
I'm also confused why you expect an update on a closed issue.
Consider this. An action is used to fetch data. The data is agnostic and could be used as state in multiple areas based on some criteria held in a different state.
A good example of this is using PostreSQL notifications. The table name and id is sent to the client. The client says, ok, I am currently displaying data from that table so I want it. The action is called to fetch the data. The action then calls the mutation. The mutation now must decide if the data should be retained based on filtering kept in a different state and it needs rootState to do this.
Now, you might ask why not do the filtering right at the action where it has access to rootState. Say there are 4 different states that could potentially use this data and each of them have their own filtering criteria. That's a lot of logic to handle a "what-if" scenario in an action. Whereas, each mutation can cherry-pick it's own data with either accept or not. The logic is better in the mutation which is more readable and decisive and less prone to bugs.
I agree with @hawkeye64 it makes a lot more sense to do sync data massaging in a mutation.
Anyway, I won't waste time debating this. Many people here tried presenting valid arguments in favor of adding rootState
to mutations, but it's evident (in this issue and others) these debates always end up with the same answer: "you are holding it wrong".
Sorry to revive this but in the documentation it says (i think) that actions are for async, so it does not discourage the direct use of mutations, in that case it seems ok to have rootState in there.
@hawkeye64 if you use the data in multiple spots. have you considered to store the data in one place and use getters in the different places that depend on it ?
@jeduden That's exactly what I do. But it could have been even more simplified in the mutation (it's supposed to be a mutation of the data!) if it had access to rootState.
It's possible to access it via this.state
inside a mutation (since this
refers to the vuex store), not sure if this is best practice though.
@Simonwep Brilliant! I can confirm that it works. No need to hassle with actions in this case. It's not an async ajax call anyway.
The alternative is to use a plugin. I am using it to sync things between different namespaced store modules. With the risk of triggering infinite loops, but that's a risk I can take.
It's possible to access it via
this.state
inside a mutation (sincethis
refers to the vuex store), not sure if this is best practice though.
@Simonwep didn't worked for me. I've got error Cannot read property 'state' of undefined
. I think I will pass rootState from action to my mutation.
It's possible to access it via
this.state
inside a mutation (sincethis
refers to the vuex store), not sure if this is best practice though.@Simonwep didn't worked for me. I've got error
Cannot read property 'state' of undefined
. I think I will pass rootState from action to my mutation.
Does your mutation look like this:
mutation: (state, payload) => { state.value = payload }
or this:
mutation(state, payload) { state.value = payload }
The binding of 'this' is different for arrow functions. If yours is the former, try changing to the second function type.
You do not need to access a root module from a module, you should call specific mutation using {root: true}. commit('nameModule/COMMIT_NAME', data, { root: true })
Hi,
I am currently using
vuex 2.0.0-rc.6
and trying to get the rootState in a mutation method from within a module, like so:and then
store.commit('increment', {by: 2})
As you can see the rootState is undefined. Any idea why this happened? I am referring the code from http://vuex.vuejs.org/en/modules.html