Vuex module breaks on getters declaration part - vue.js

The Vuex store was starting to get a bit crowded so I decided to break it into modules. However, the code breaks after compiling with the following error
Uncaught TypeError: Cannot read property 'customS' of null
This is my invitations module
export const state = {
customS: null };
export const getters = {
getInvitations: (state) => state.customS, };
export const mutations = {
setcustomS: (state, customS) => state.customS= customS};
and this is how I import it inside the store
import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios';
import createPersistedState from 'vuex-persistedstate';
Vue.use(Vuex);
// Load store modules dynamically.
const requireContext = require.context('./modules', false, /.*\.js$/);
const modules = requireContext.keys()
.map(file =>
[
file.replace(/(^.\/)|(\.js$)/g, ''),
requireContext(file),
]
)
.reduce((modules, [
name,
module,
]) => {
if (module.namespaced === undefined) {
module.namespaced = true;
}
return { ...modules, [name]: module, };
}, {});
console.log(modules);
export const store = new Vuex.Store({
plugins: [
createPersistedState(),
],
modules,
});
Project is using the laravel and vue combination. Thanks in advance.

Related

Vuex unable to use modules

I am using Vue with Webpacker with Rails. I am having some problem with Vuex, specifially on using modules.
application.js:
import store from '../store/store'
Vue.prototype.$store = store;
document.addEventListener('turbolinks:load', () => {
axios.defaults.headers.common['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').getAttribute('content')
const app = new Vue({
el: '[data-behavior="vue"]',
store
})
})
store.js:
import Vue from 'vue/dist/vue.esm'
import Vuex from 'vuex';
import axios from 'axios';
import itemstore from'./modules/itemstore'
Vue.use(Vuex)
import VueAxios from 'vue-axios'
Vue.use(VueAxios, axios)
const store = new Vuex.Store({
............
modules: {
itemstore
}
})
export default store;
itemstore.js:
import axios from 'axios';
const itemstore = {
state: {
items: [],
},
actions: {
loadItems ({ commit }) {
axios
.get('/items.json')
.then(r => r.data)
.then(items => {
commit('SET_ITEMS', items);
})
}
},
mutations: {
SET_ITEMS (state, items) {
state.items = items
}
},
}
export default itemstore;
In my component:
mounted () {
this.$store.dispatch('loadItems')
},
computed: {
...mapState([
'items'
]),
}
First to get the main store imported I need Vue.prototype.$store = store;
Secondly once i move those states, actions and mutations from store.js to itemstore.js, items gets undefined. What am I doing wrong?
The namespaced setting will cause the actions, mutations and setters of a store to be namespaced based on the module name. The state of a module, however, is always separated off into its own subtree within state, even if namespacing is not being used.
So this won't work:
...mapState([
'items'
]),
This is looking for an items property in the root state.
Instead you can use something like:
...mapState({
items: state => state.itemstore.items
})
You might be tempted to try to write it like this:
...mapState('itemstore', ['items'])
However, passing the module name as the first argument to mapState will only work with namespaced modules.

vuex unknown local mutation type: updateValue, global type: app/updateValue. Mutations don't work

I want to apply mutations through actions to a variable in my vuejs application. But I get this error saying [vuex] unknown local mutation type: updateValue, global type: app/updateValue
Here is my store folder structure:
-store
-modules
-app
-actions.js
-getters.js
-mutations.js
-state.js
-index.js
-actions.js
-getters.js
-mutations.js
-state.js
-index.js
This is my ./store/index.js file:
import Vue from 'vue'
import Vuex from 'vuex'
import actions from './actions'
import getters from './getters'
import modules from './modules'
import mutations from './mutations'
import state from './state'
Vue.use(Vuex)
const store = new Vuex.Store({
namespaced: true,
actions,
getters,
modules,
mutations,
state
})
export default store
This is my ./store/modules/index.js:
const requireModule = require.context('.', true, /\.js$/)
const modules = {}
requireModule.keys().forEach(fileName => {
if (fileName === './index.js') return
// Replace ./ and .js
const path = fileName.replace(/(\.\/|\.js)/g, '')
const [moduleName, imported] = path.split('/')
if (!modules[moduleName]) {
modules[moduleName] = {
namespaced: true
}
}
modules[moduleName][imported] = requireModule(fileName).default
})
export default modules
This is my ./store/modules/app/actions.js:
export const updateValue = ({commit}, payload) => {
commit('updateValue', payload)
}
This is my ./store/modules/app/getters.js:
export const value = state => {
return state.wruValue;
}
This is my ./store/modules/app/mutations.js:
import { set, toggle } from '#/utils/vuex'
export default {
setDrawer: set('drawer'),
setImage: set('image'),
setColor: set('color'),
toggleDrawer: toggle('drawer')
}
export const updateValue = (state, payload) => {
state.wruValue = payload * 12;
}
This is my ./store/modules/app/state.js:
export default {
drawer: null,
color: 'green',
wruValues:1,
wruValue: 1,
}
and finally this is my vue component:
<v-btn #click="updateValue(10)">
SHOW
</v-btn>
import { mapActions } from 'vuex';
...mapActions ('app',[
'updateValue'
]),
So when I click on the button I expect to see the wruValue to change (I print the value somewhere else for testing purposes) but instead I get the error mentioned above. What's wrong with my code?
commit('updateValue', payload, {root: true})
But I find your use of namespacing odd. For my projects, I don't separate out files for getters, actions, etc, I separate out tasks, projects, companies, etc. But if it works for you, that's fine. It doesn't seem like the issue. If you still get an error, you might need to change "updateValue" to "mutations/updateValue" or something.
You should use this project structure:
src/store/modules/app.js
export const state = {
drawer: null,
color: 'green',
wruValues: 1,
wruValue: 1
}
export const mutations = {
UPDATE_VALUE: (state, payload) => {
state.wruValue = payload * 12
}
}
export const actions = {
updateValue: ({ commit }, payload) => {
commit('UPDATE_VALUE', payload)
}
}
export const getters = {
getWruValue: (state) => state.wruValue
}
src/store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const requireContext = require.context('./modules', true, /.*\.js$/)
const modules = requireContext.keys()
.map(file =>
[file.replace(/(^.\/)|(\.js$)/g, ''), requireContext(file)]
)
.reduce((modules, [name, module]) => {
if (module.namespaced === undefined) {
module.namespaced = true
}
return { ...modules, [name]: module }
}, {})
export default new Vuex.Store({
modules
})
src/main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store/'
Vue.config.productionTip = false
new Vue({
router,
store,
render: h => h(App)
}).$mount('#app')
src/App.vue
<template>
<div id="app">
<button #click="updateValue(10)">
SHOW
</button>
</div>
</template>
<script>
import { mapActions } from 'vuex'
export default {
methods: {
...mapActions('app', ['updateValue'])
}
}
</script>
Then if you want to add a new store namespace, u need to put it inside of src/modules folder.

Use Vuex classic mode in Nuxt application

I'm rewriting Vue application to Nuxt architecture because we want SSR. However I don't want to rewrite Vuex store file which is:
import Vue from "vue";
import Vuex from "vuex";
import vuexI18n from "vuex-i18n/dist/vuex-i18n.umd.js";
import toEnglish from "../translations/toEnglish";
import toSpanish from "./../translations/toSpanish";
import toGerman from "./../translations/toGerman";
import toRussian from "./../translations/toRussian";
Vue.use(Vuex);
const store = new Vuex.Store({
state: {
currentLanguage: ''
},
mutations: {
changeLang: (state, response) => {
if(response) {
state.currentLanguage = response;
Vue.i18n.set(response);
console.log(response);
}
}
}
});
Vue.use(vuexI18n.plugin, store);
Vue.i18n.add("en", toEnglish);
Vue.i18n.add("es", toSpanish);
Vue.i18n.add("de", toGerman);
Vue.i18n.add("ru", toRussian);
export default store;
I know that Nuxt has some other approach to that but I really want to stick with above code. Unfortuenally I can't call mutation from my component by:
this.$store.commit('changeLang', lang)
it print error in console:
[vuex] unknown mutation type: changeLang
I also tried like this
this.$store.commit('store/changeLang', lang)
but error is same. How to fix it? Do I need to rewrite this vuex file in order to make it work?
I followed #Aldarund tips and changed above code to:
import Vue from "vue";
import Vuex from "vuex";
import vuexI18n from "vuex-i18n/dist/vuex-i18n.umd.js";
import toEnglish from "../translations/toEnglish";
import toSpanish from "./../translations/toSpanish";
import toGerman from "./../translations/toGerman";
import toRussian from "./../translations/toRussian";
const store = () => {
return new Vuex.Store({
state: () => ({
currentLanguage: ''
}),
mutations: {
changeLang: (state, response) => {
if (response) {
state.currentLanguage = response;
Vue.i18n.set(response);
console.log(response);
}
}
}
})
};
Vue.use(vuexI18n.plugin, store);
Vue.i18n.add("en", toEnglish);
Vue.i18n.add("es", toSpanish);
Vue.i18n.add("de", toGerman);
Vue.i18n.add("ru", toRussian);
export default store;
now error is
Uncaught TypeError: store.registerModule is not a function
It's probably because of Vue.use(vuexI18n.plugin, store);.
You need to use classic mode.
Classic (deprecated): store/index.js returns a method to create a
store instance
So it should look like this, no vuex use, on import of Vue. And it must be a function that crestr store, not plain vuex object
import Vuex from 'vuex'
const createStore = () => {
return new Vuex.Store({
state: () => ({
counter: 0
}),
mutations: {
increment (state) {
state.counter++
}
}
})
}
export default createStore
Docs https://nuxtjs.org/guide/vuex-store/#classic-mode
As for plugin e.g. vyexi18 you need to move that code into plugin file and get created store object from context https://nuxtjs.org/guide/plugins/
export default ({ store }) => {
Your vuex18initcode
}

vuex dynamic module register shows object empty

I have registered vuex module with this function this.$store.registerModule(this.name, 'some_module') module created but showing empty in vuedevtools.
and I'm trying to dispatch with this code this.$store.dispatch(this.name+'/some_action', this.id)this return error unknown action type
please help anyone how to create vuex module dynamically.
store index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// Load store modules dynamically.
const requireContext = require.context('./modules', false, /.*\.js$/)
const modules = requireContext.keys()
.map(file =>
[file.replace(/(^.\/)|(\.js$)/g, ''), requireContext(file)]
)
.reduce((modules, [name, module]) => {
if (module.namespaced === undefined) {
module.namespaced = true
}
return { ...modules, [name]: module }
}, {})
export default new Vuex.Store({
modules
})
somo_module.js
import Vue from 'vue'
import axios from 'axios'
import * as types from '../mutation-types'
// state
export const state = {
count: ''
}
// getters
export const getters = {
count: state => state.count
}
// mutations
export const mutations = {
[types.GET_COUNT] (state, data ) {
state.count = data
}
}
// actions
export const actions = {
async some_action ({ commit }, payload) {
try {
const { data } = await axios.post('/count/'+payload)
commit(types.GET_COUNT, data )
// console.log(data)
} catch (e) {
}
}
}
First you have to make sure that this.name !== undefined then you can dynamically add the module to the store like this (according to the DOC and API Reference)
this.$store.registerModule(this.name, {
namespaced: true,
state: {
some_items: []
},
getters: {
items: state => state.some_items
},
actions: {
someAction () {}
},
mutations: {}
})
And use it as you always do this.$store.dispatch('yourModule/someAction')
If you wish you can also update your store index.js like this in order to register modules that have been exported by default as object
myModule.js
const state = {}
const actions = {}
const getters = {}
const mutations = {}
const module = {
namespaced: true,
state,
getters,
mutations,
actions
}
export default module
store index.js
As you can see below i only made a small changes to the reduce method
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
// Load store modules dynamically.
const requireContext = require.context('./modules', false, /.*\.js$/)
const modules = requireContext.keys()
.map(file =>
[file.replace(/(^.\/)|(\.js$)/g, ''), requireContext(file)]
)
.reduce((modules, [name, mod]) => {
let module = mod.default || mod
if (module.namespaced === undefined) {
module.namespaced = true
}
return { ...modules, [name]: module }
}, {})
export default new Vuex.Store({
modules
})

Lazy loading on vuex modules

I’m trying to use lazy loading with my vuex modules like this article : https://alexjoverm.github.io/2017/07/16/Lazy-load-in-Vue-using-Webpack-s-code-splitting/
Here is my old store\index.js :
import Vue from 'vue';
import Vuex from 'vuex';
import app from './modules/app';
import search from './modules/search';
import identity from './modules/identity';
import profil from './modules/profil';
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
app,
search,
identity,
profil,
},
});
I tried to do this :
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
const store = new Vuex.Store();
import('./modules/app').then((appModule) => {
store.registerModule('app', appModule);
});
import('./modules/search').then((searchModule) => {
store.registerModule('search', searchModule);
});
import('./modules/identity').then((identityModule) => {
store.registerModule('identity', identityModule);
});
import('./modules/profil').then((profilModule) => {
store.registerModule('profil', profilModule);
});
export default store;
But now I have a lot of error like “TypeError: _vm.consultList is undefined", consultList is a mapState variable, I also have same errors on my mapActions
Did I’ve done something wrong ?
All of those modules will be registered when app is loaded any because you most likely add the store to your initial vue instance. How I dynamically loading my vuex module is via the router:
{
path: "/orders/active",
name: "active-orders",
component: ActiveOrders,
props: true,
beforeEnter: (to, from, next) => {
importOrdersState().then(() => {
next();
});
}
},
Then also inside my router file I added:
const importOrdersState = () =>
import("#/store/orders").then(({ orders }) => {
if (!store.state.orders) store.registerModule("orders", orders);
else return;
});