Access module from Vuex Store - vue.js

I have the following module:
export const ProfileData = {
state: {
ajaxData: null;
},
getters: {/*getters here*/},
mutations: {/*mutations here*/},
actions: {/*actions here*/}
}
and this module is registered in my global store:
import {ProfileData} from './store/modules/ProfileData.es6'
const store = new Vuex.Store({
modules: {
ProfileData: ProfileData
}
});
I have also used the Vue.use(Vuex) and set the store in new Vue({ store: store}) properly. However, when I try to access the ajaxData belonging to the ProfileData module, in one of my components via this.$store.ProfileData.ajaxData, the console shows an undefined error. The same goes for reading the this.$store.ProfileData or this.$store.ajaxData, while this.$store is defined and I am already able to read it. I also see the ProfileData object added to the _modules property of the store in browser's console.
What is that I am doing wrong to access the modules registered to the Vuex? How can I access those?

Directly accessing state of Vuex module
The format to access a Module's local state is $store.state.moduleName.propertyFromState.
So you would use:
this.$store.state.ProfileData.ajaxData
Demo:
const ProfileData = {
state: {ajaxData: "foo"}
}
const store = new Vuex.Store({
strict: true,
modules: {
ProfileData
}
});
new Vue({
store,
el: '#app',
mounted: function() {
console.log(this.$store.state.ProfileData.ajaxData)
}
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/vuex"></script>
<div id="app">
<p>ajaxData: {{ $store.state.ProfileData.ajaxData }}</p>
</div>
Getters, Actions and Mutators of modules, how to directly access them?
It depends if they are namespaced or not. See demo (explanation in comments):
const ProfileDataWithoutNamespace = {
state: {ajaxData1: "foo1"},
getters: {getterFromProfileDataWithoutNamespace: (state) => state.ajaxData1}
}
const ProfileDataWithNamespace = {
namespaced: true,
state: {ajaxData2: "foo2"},
getters: {getterFromProfileDataWithNamespace: (state) => state.ajaxData2}
}
const store = new Vuex.Store({
strict: true,
modules: {
ProfileDataWithoutNamespace,
ProfileDataWithNamespace
}
});
new Vue({
store,
el: '#app',
mounted: function() {
// state is always per module
console.log(this.$store.state.ProfileDataWithoutNamespace.ajaxData1)
console.log(this.$store.state.ProfileDataWithNamespace.ajaxData2)
// getters, actions and mutations depends if namespace is true or not
// if namespace is absent or false, they are added with their original name
console.log(this.$store.getters['getterFromProfileDataWithoutNamespace'])
// if namespace is true, they are added with Namespace/ prefix
console.log(this.$store.getters['ProfileDataWithNamespace/getterFromProfileDataWithNamespace'])
}
})
<script src="https://unpkg.com/vue/dist/vue.min.js"></script>
<script src="https://unpkg.com/vuex"></script>
<div id="app">
<p>Check the console.</p>
</div>

I see you added the module using key:value, and the key to access your module is Profile. Try to call your module using it, or define the module setting directly, without Profile key:
modules: {
ProfileData
}

Related

Struggling to access state of vuex

I'm going crazy over this as I can't understand what I might be missing.. so I'm basically using vuex to store the state of the user. I've setup a route and use Axios to make a call to this route to retrieve some info from the user. I can see in vue dev tools that the state and everything are set I'm just having a real hard time accessing it. If I do the following console.log(this.$store.state.baseSettings) in mounted then this shows the following:
Now I would have thought by adding .user onto that console.log I'd get exactly what I need but it shows an empty object.
I have also tried the following:
computed: {
user() {
return this.$store.state.baseSettings.user;
},
},
This works if I do {{ user }} in the template itself but if I try and access this.user in computed, mounted, or any methods I also get an empty object. Is there any reason for this? Am I missing something simple/obvious here?
Any help would be greatly appreciated! Here's my full code:
app.js:
import Vue from 'vue';
import Vuetify from 'vuetify';
import router from '../../router';
import store from './store';
import {userComputed, settingsMethods} from './store/helpers';
import App from '../App.vue';
new Vue({
router,
store,
vuetify: new Vuetify(),
render: h => h(App),
computed: {
...userComputed,
},
methods: {
...settingsMethods,
},
mounted() {
return this.getAllSettings();
},
}).$mount('#app');
App.vue
<template>
<v-app>
{{ user }}
<v-main :class="!user ? 'background-img' : null">
<v-container fluid>
<nav-bar/>
<router-view/>
</v-container>
</v-main>
</v-app>
</template>
<script>
export default {
computed: {
user() {
// Works but only in above <template></template>
return this.$store.state.baseSettings.user;
},
},
mounted() {
// Returns object with user data (see screenshot).
console.log(this.$store.state.baseSettings);
// Empty object!
console.log(this.$store.state.baseSettings.user);
// Empty object
console.log(this.user)
}
}
</script>
baseSettings.js:
const state = {
user: {},
};
const getters = {
getUser: state => _.keys(state.user),
};
const actions = {
getAllSettings({ commit }) {
return axios.get('settings').then(baseSettings => {
commit('setUser', _.get(baseSettings, 'data.user', {}));
});
},
};
const mutations = {
setUser(state, user) {
state.user = user;
},
};
export default {
namespaced: true,
state,
getters,
actions,
mutations,
};
helpers.js:
import { mapActions, mapState } from 'vuex';
export const userComputed = {
...mapState('baseSettings', ['user']),
};
export const settingsMethods = {
...mapActions('baseSettings', ['getAllSettings']),
};
index.js
import Vue from 'vue';
import Vuex from 'vuex';
import baseSettings from '../modules/baseSettings';
Vue.use(Vuex);
const debug = process.env.NODE_ENV !== 'production';
export default new Vuex.Store({
modules: {
baseSettings,
},
strict: debug,
});
Thanks so much!
This seems to be an unfulfilled promise problem.
You do both, retrieving the getAllSettings() as well as trying to access the $store independently of each other at the same lifecycle step. Therefore it is not guaranteed that the Axios call has already reported data and saved it to the store when you try to access it from there (resulting in the empty object at runtime).
However since the computed property reruns once the dependant variable changes, it will display correct in your component, as this happens after the mounted() lifecycle step, when the Axios call has run through.

How to use mapGetters with Vuex Modules

i have added modules in store/index.js
import NavMessage from './nav/message/index';
new Vuex.Store({
modules: {
NavMessage,
},
});
my message/index.js
import state from './state';
import getters from './getters';
import mutations from './mutations';
export default {
state,
getters,
mutations,
};
here is getters
const getters = () => ({
getCount: state => {
return state.count;
},
});
export default getters;
i am trying to get data from NavMessage/getCount
...mapGetters({
count: 'NavMessage/getCount',
}),
but i am getting error unknown getter: NavMessage/getCount
help me thank
Below is a working example.
I've made two important changes:
I've added namespaced: true to the module.
I've removed the wrapper function from around the getters.
If you don't want to use namespacing then you'll need to change the mapGetters argument to count: 'getCount' instead. The NavMessage/ prefix is only required with namespacing.
const mapGetters = Vuex.mapGetters
const state = {
count: 6
}
const getters = {
getCount: state => {
return state.count
}
}
const mutations = {}
const NavMessage = {
namespaced: true,
state,
getters,
mutations
}
const store = new Vuex.Store({
modules: {
NavMessage
}
})
const app = new Vue({
store,
computed: {
...mapGetters({
count: 'NavMessage/getCount',
})
}
})
console.log(app.count)
<script src="https://unpkg.com/vue#2.6.10/dist/vue.js"></script>
<script src="https://unpkg.com/vuex#3.1.2/dist/vuex.js"></script>
You've tagged the question with Nuxt. If you are using Nuxt I strongly suggest reading their guide to using the store:
https://nuxtjs.org/guide/vuex-store
Nuxt does things a little differently but as far as I'm aware you still shouldn't have a function wrapper around your getters. The namespaced: true will be added automatically and you shouldn't need to create the new Vuex.Store yourself. Nuxt creates the store itself and adds modules based on the folder structure.

Using store in component with Quasar

I'm trying to implement Vuex store in a Quasar project. I created a new project using the quasar-cli and checked the Vuex box. I then followed the guide on the quasar website (https://quasar.dev/quasar-cli/cli-documentation/vuex-store)
and created a new store using quasar new store test
I then registered the store module in the store/index.js
export default function(/* { ssrContext } */) {
const Store = new Vuex.Store({
modules: {
test
// example
},
Afterwards, I added the mutation and state code, exactly as referenced in the tutorial.
Then I created a new component (test) and added the code as explained.
However, I am unable to use this.$store, and receive a warning from my IDE that $store is not defined.
I have read the Vuex documentation, which writes that it is possible to pass the state to all components by adding the state to the object in main.js. As far as i can see, quasar does this already.
So, what am I doing wrong and how can you use store without manually importing it for every single component?
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
// general state
app
},
mutations: {
someMutation (state, store) {
}
},
actions: {
someAction ({commit}) {
},
})
export default store
Also don't forget to include this store in app.js
Vue.use(Vuex) was missing
Vuex provides a mechanism to "inject" the store into all child components from the root component with the store option (enabled by Vue.use(Vuex))
It took me a while to get it working but here is an example of my state
user :
{
uid: '',
name: '',
accountType: ''
}
}
const mutations = {
setName (state, val) {
state.user.name = val
},
setUID (state, val) {
state.user.uid = val
},
setAccountType (state, val) {
state.user.accountType = val
}
}
const actions = {
}
const getters = {
user: (state) => {
return state.user
}
}
export default {
namespaced: true,
state,
mutations,
actions,
getters
}
then in each file if you want to access this information you have to use
computed : {
user () {
return this.$store.getters['user/user']
}
}
I wanted to display this information in my tags and can do so with
<template>
<div class="user-profile">
{{ user.name }}
{{ user.email }}
{{ user.accountType }}
</div>
</template>
hope that helps.
note rather than a folder with my modules I have it all in one file 'store-user.js' and in my store/index.js I have
import user from './store-user'
and
export default function (/* { ssrContext } */) {
const Store = new Vuex.Store({
modules: {
user
}
// enable strict mode (adds overhead!)
// for dev mode only
strict: process.env.DEV
})
return Store
}

How to pass store values in components

I want to pass values in the store.state in components and got an error:
[Vue warn]: Error in render: "TypeError: Cannot read property 'state' of undefined"
So I called the value in the component directly and it doesn't work.
const store = new Vuex.Store({
state: {
filter: {
selected: false,
value: 'test'
}
},
});
new Vue({
el: '#app',
template: `<div id="app"><div :selected="this.$store.state.filter.selected">Option</div></div>`
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://unpkg.com/vuex#3.0.1/dist/vuex.js"></script>
<div id="app"></div>
Vue
const store = new Vuex.Store({
state: {
filter: {
value: 'test',
selected: true
}
},
mutations: {},
actions: {},
getters: {}
});
HTML
<option :selected="store.state.filter.selected">{{store.state.filter.value}}</option>
Can I use it this way, or I need to think differently and how? Thanks.
My current solution is store the value in computed variables, but would there be a way to pass Vuex store values into a component directly?
computed: {
filter () {
return storeLogs.state.filter;
}
}
<option :selected="filter.selected">{{filter.value}}</option>
Two things:
You must pass your store object to the Vue constructor
There's no need to reference "this" in your template
const store = new Vuex.Store({
state: {
filter: {
selected: false,
value: 'test'
}
},
});
new Vue({
store, // add store object to Vue
el: '#app',
template: `<div id="app"><div selected="$store.state.filter.selected">Option</div></div>`
});
You can also use mapState like this in your .vue file:
<!-- MyComponent.vue -->
<template>
<option :selected="filter.selected">{{filter.value}}</option>
</template>
<script>
import { mapState } from 'vuex';
export default {
name : 'MyComponent',
computed() {
...mapState(['filter'])
}
}
</script>

How to access Vuex module actions from a component

I define a store with two modules, and I'm trying to access one module action, I tried to do
this.$store.dispatch('load');
But I get:
[vuex] unknown action type: load
I tried another options, thing that I found in google , but nothing worked, what is the right way to access module actions?
This is my code:
Vuex definition:
let session = require('./store/session.js');
let options = require('./store/options.js');
const store = new Vuex.Store({
modules: {
session: session,
options: options,
},
});
options.js
export default {
state: {
data: null,
},
mutations: {
setOptions (state, payload) {
console.log(payload);
}
},
actions: {
load( { commit }) {
$.getJSON('options')
.then(function (data) {
commit('setOptions', data);
});
}
},
getters: {
}
}
and my app component:
export default {
beforeCreate() {
this.$store.dispatch('load');
}
}
my vue build:
new Vue({
el: "#app",
router,
store,
render: h => h(App)
});
I would consider using the mapActions helper from vuex. Documentation for this can be found at https://vuex.vuejs.org/guide/actions.html#dispatching-actions-in-components .
example from this page is as follows:
import { mapActions } from 'vuex'
export default {
// ...
methods: {
...mapActions([
'increment', // map `this.increment()` to `this.$store.dispatch('increment')`
// `mapActions` also supports payloads:
'incrementBy' // map `this.incrementBy(amount)` to `this.$store.dispatch('incrementBy', amount)`
]),
...mapActions({
add: 'increment' // map `this.add()` to `this.$store.dispatch('increment')`
})
}
}
I solver the problem
Instead of doing
let options = require('./store/options.js');
I did:
import options from './store/options.js'
Now it works