I know I can access a module's state from a mutation in the root store like this:
state.moduleName.moduleStateProp
But is it also possible to access moduleName dynamically?
I thought of having a shared mutation in the root store which gets committed from actions in different modules. The root store mutation then dynamically mutates the state property of the modules' state which committed the mutation.
I read that there's a context object available in an action and I tried retrieving the current module's scoped state from there.
That's what I've tried:
Assume I have store modules ModuleA and ModuleB with a state and action like this:
const state = {
moduleProp: null, // named like this in both modules
};
const actions = {
someAsyncAction({ state, commit }) {
axios.get('/my/api/url/')
.then(res => {
const payload = {'context': state, 'data': res.data};
commit('someMutation', payload);
});
};
And a shared mutation in root store like this
mutations: {
someMutation(state, payload) {
// Do something with payload.data
// Then assign mutated payload.data to module state prop
state.payload.context.moduleProp = payload.data; // A
},
}
When trying it like this I get TypeError: Cannot read properties of undefined (reading 'context') in the root store on line A.
Question:
Is it at all possible to retrieve the name of the module that committed the mutation? If not, why shouldn't it be possible?
Thank you in advance.
Related
Vuelidate 2 (aka "Next") is supposed to support using Vuelidate outside of Vue components. I'd like to store a global validation state (v$) in a Pinia store instead of in one or more components, using a mapped state property. One of the authors offered an example for doing this with the Composition API, where you pass a reactive state to useVuelidate():
const formState = reactive({})
const rules = {}
const state = {
someProperty: '',
validations: useVuelidate(rules, formState)
}
export {
state
}
I'm still using the Options API and Vue 2, but haven't been able to figure out to "translate" the above for the Options API. I've tried passing mapped state properties, but they get flagged as "undefined". E.g., something like this in my root component (note: you have to install the CompositionAPI module and use setup to use Vuelidate 2 in Vue 2):
setup: () => ({
v$: useVuelidate(this.mappedValidationRulesObject, this.mapped.StoreState)
})
Does anyone know how to do this?
I have a Quasar app running Vue 3 and Vuex 4
During app creation my store is accessible when printed and shows the full object. The store is set in app creation with
app.use(store, storeKey)
Which produces a fully hydrated object
{_committing: false, _actions: {…}, _actionSubscribers: Array(0),
_mutations: {…}, _wrappedGetters: {…}, …}
The vuex state works perfectly in my router/index with
export default route (function ({ store }) {
const isLoggedIn = store.state.auth.loggedIn;
This example correctly show the loggedIn value I set in my state, so I assume the vuex side must be setup correctly
My problem is I haven't been able to find a way to access my state from a Vue component
I tried with useStore() in my setup function
setup () {
const $store = useStore()
const loggedIn = computed({
get: () => $store.state.auth.loggedIn,
set: () => { $store.commit('login') }
})
Which produces a console error that
injection "store" not found.
and a loggedIn object of
ComputedRefImpl {dep: undefined, _dirty: true, __v_isRef: true,
effect: ReactiveEffect, _setter: ƒ, …}
I also tried using this.$store in the computed object
computed : {
loggedIn () {
return this.$store.state.auth.loggedIn
}
}
But I just get the error that
Property '$store' does not exist on type '{ loggedIn(): any; }'.
I assume I must be missing something silly. I just want to call $store.commit('login') or $store.dispatch from the single file component
How can I access my Vuex store from the single file .Vue component?
Per user10031694 I tried and got a reader working with mapState
computed : mapState({
loggedIn: state => state.auth.loggedIn,
Which gets {{loggedIn}} to show the correct field
In my application I have a Vuex 4 store and a Vue 3 Composition Api setup() method.
In the stores action I use axios to make an api call to get a list of bill payments.
The getAllBills action does not live directly in my Store.js file, it exists as a module.
getAllBills({ commit }) {
BillApiCalls.getBills().then(res => {
commit('GET_ALL_BILLS', res.data)
}).catch(error => console.log(error))
},
Then in my Bill.vue file I have the setup() method and am trying to access the data to be used throughout the same Bill.vue file.
setup () {
//Vuex store
const store = useStore();
const billPayments = store.dispatch('payment/getAllBills').then(res => console.log(res));
}
If I check the console from the above .then() res returns as undefined. If I remove the .then() from the billPayments declaration and just do:
console.log(billPayments)
In the console I get
Promise {<pending>}.
Current Store:
import { bill } from './modules/bill.module';
const store = createStore({
modules: {
bill
}
});
The endpoint is working, if I use Postman all of my data is returned as expected but I am having trouble figuring out how to access that data using a dispatched action with the composition api.
The Vuex 4 docs don't mention how to actually resolve the promise to access the data to be used throughout the same component.
An action isn't generally supposed to return data it acts on, data is a part of the state and should be accessed there; this is what another answer shows:
await store.dispatch('payment/getAllBills')
console.log(store.state.payment.bills);
The action doesn't chain promises so it cannot be correctly used. It should be:
return BillApiCalls.getBills()...
Or prefer async..await together with promise to avoid some common mistakes that can be made with raw promises.
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
Is it possible to dispatch an action between namespaced modules?
E.g. I have Vuex modules "gameboard" and "notification". Each are namespaced. I would like to dispatch an action from the gameboard module in the notification module.
I thought I could use the module name in the dispatch action name like this:
// store/modules/gameboard.js
const actions = {
myaction ({dispatch}) {
...
dispatch('notification/triggerSelfDismissingNotifcation', {...})
}
}
// store/modules/notification.js
const actions = {
triggerSelfDismissingNotification (context, payload) {
...
}
}
But when I try to do this I get errors that make me think Vuex is trying to dispatch an action within my gameboard module:
[vuex] unknown local action type: notification/triggerSelfDismissingNotification, global type: gameboard/notification/triggerSelfDismissingNotification
Is there a way of dispatching actions from a given Vuex module to another, or do I need to create some kind of a bridge in the root Vuex instance?
You just need to specify that you're dispatching from the root context:
// from the gameboard.js vuex module
dispatch('notification/triggerSelfDismissingNotifcation', {...}, {root:true})
Now when the dispatch reaches the root it will have the correct namespace path to the notifications module (relative to the root instance).
This is assuming you're setting namespaced: true on your Vuex store module.
dispatch('mobuleB/actionB', null, { root: true })