Lazy loading on vuex modules - vuejs2

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;
});

Related

How does Vuex 4 createStore() work internally

I am having some difficulty understanding how Veux 4 createStore() works.
In /store/index.js I have (amongst a few other things):
export function createVuexStore(){
return createStore({
modules: {
userStore,
productStore
}
})
}
export function provideStore(store) {
provide('vuex-store', store)
}
In client-entry.js I pass the store to makeApp() like this:
import * as vuexStore from './store/index.js';
import makeApp from './main.js'
const _vuexStore = vuexStore.createVuexStore();
const {app, router} = makeApp({
vuexStore: _vuexStore,
});
And main.js default method does this:
export default function(args) {
const rootComponent = {
render: () => h(App),
components: { App },
setup() {
vuexStore.provideStore(args.vuexStore)
}
}
const app = (isSSR ? createSSRApp : createApp)(rootComponent);
app.use(args.vuexStore);
So, there is no store that is exported from anywhere which means that I cannot import store in another .js file like my vue-router and access the getters or dispatch actions.
import {store} '../store/index.js' // not possible
In order to make this work, I did the following in the vue-router.js file which works but I don't understand why it works:
import * as vuexStore from '../store/index.js'
const $store = vuexStore.createVuexStore();
async function testMe(to, from, next) {
$store.getters('getUser'); // returns info correctly
$store.dispatch('logout'); // this works fine
}
Does Veux's createStore() method create a fresh new store each time or is it a reference to the same store that was created in client-entry.js? It appears it is the latter, so does that mean an application only has one store no matter how many times you run createStore()? Why, then, does running createStore() not overwrite the existing store and initialise it with blank values?
createStore() method can be used on your setup method.
On your main.js, you could do something like this
import { createApp } from 'vue'
import store from './store'
createApp(App).use(store).use(router).mount('#app')
store.js
import { createStore } from 'vuex';
export default createStore({
state: {},
mutations: {},
actions: {},
});
To access your store, you don't need to import store.js anymore, you could just use the new useStore() method to create the object. You can directly access your store using it just as usual.
your-component.js
<script>
import { computed } from "vue";
import { useStore } from "vuex";
export default {
setup() {
const store = useStore();
const isAuthenticated = computed(() => store.state.isAuthenticated);
const logout = () => store.dispatch("logout");
return { isAuthenticated, logout };
},
};
</script>
To use your store in the route.js file, you could simply imported the old fashion way.
route.js
import Home from '../views/Home.vue'
import store from '../store/'
const logout = () => {
store.dispatch("auth/logout");
}
export const routes = [
{
path: '/',
name: 'Home',
component: Home
}
]

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.

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 unknown action type when attempting to dispatch action from vuejs component

I'm using laravel, vue and vuex in another project with almost identical code and it's working great. I'm trying to adapt what I've done there to this project, using that code as boilerplate but I keep getting the error:
[vuex] unknown action type: panels/GET_PANEL
I have an index.js in the store directory which then imports namespaced store modules, to keep things tidy:
import Vue from "vue";
import Vuex from "vuex";
var axios = require("axios");
import users from "./users";
import subscriptions from "./subscriptions";
import blocks from "./blocks";
import panels from "./panels";
Vue.use(Vuex);
export default new Vuex.Store({
state: {
},
actions: {
},
mutations: {
},
modules: {
users,
subscriptions,
blocks,
panels
}
})
panels.js:
const state = {
panel: []
}
const getters = {
}
const actions = {
GET_PANEL : async ({ state, commit }, panel_id) => {
let { data } = await axios.get('/api/panel/'+panel_id)
commit('SET_PANEL', data)
}
}
const mutations = {
SET_PANEL (state, panel) {
state.panel = panel
}
}
export default {
namespaced: true,
state,
getters,
actions,
mutations
}
Below is the script section from my vue component:
<script>
import { mapState, mapActions } from "vuex";
export default {
data () {
return {
}
},
mounted() {
this.$store.dispatch('panels/GET_PANEL', 6)
},
computed:
mapState({
panel: state => state.panels.panel
}),
methods: {
...mapActions([
"panels/GET_PANEL"
])
}
}
</script>
And here is the relevant code from my app.js:
import Vue from 'vue';
import Vuex from 'vuex'
import store from './store';
Vue.use(Vuex)
const app = new Vue({
store: store,
}).$mount('#bsrwrap')
UPDATE:: I've tried to just log the initial state from vuex and I get: Error in mounted hook: "ReferenceError: panel is not defined. I tried creating another, very basic components using another module store, no luck there either. I checked my vuex version, 3.1.0, the latest. Seems to be something in the app.js or store, since the problem persists across multiple modules.
Once you have namespaced module use the following mapping:
...mapActions("panels", ["GET_PANEL"])
Where first argument is module's namespace and second is array of actions to map.

state not define in vue

hello guys i follow everything provide no google but none of these working i m new to vuex 3.0.1 and vue 2.5 below of my code
import Vue from 'vue'
import App from './App'
import router from './router'
import axios from 'axios'
import store from './store'
Vue.prototype.$http = axios;
var VueResource = require('vue-resource');
Vue.use(VueResource);
router.beforeEach((to, from, next) => {
console.log(this.$store.state.authUser)// this is not working
if (to.matched.some(record => record.meta.requiresAuth) &&
(!this.$store.state.authUser ||
this.$store.state.authUser === 'null')){
const authUser = localStorage.getItem('authUser')
console.log('here log');
next({ path: '/', })
}else{
console.log('bhar else redirect');
next()
}
});
new Vue({
el: '#app',
router,
store,
template: '<App/>',
components: {
App
}
})
everything work porperly if i remove this this.$store.state.authUser it work here is my store.js file
import Vue from 'vue'
import Vuex from 'vuex'
import userStore from './user/userStore.js'
Vue.use(Vuex)
const debug = process.env.NODE_ENV !== 'production'
export default new Vuex.Store({
modules:{
userStore
},
strict:debug
})
here is my userStore
const state = {
authUser:null
}
const mutations = {
SET_AUTH_USER(state,userObj){
state.authUser = userObj
}
}
const actions = {
setUserObject :({commit},userObj) =>{
commit('SET_AUTH_USER',userObj)
}
}
export default {
state, mutations, actions
}
here is my login succcess from where i trie to dispatch value in store note i have value in store
this.$store.dispatch('setUserObject',response.data.id)
i does everything properly but don't know why it throw error Cannot read property 'state' of undefined
You are accessing your store in the router's beforeEach guard using this.$store. But this is not your vue instance and has no $store property.
Since you are importing the store using import store from './store', you can use that store import to access your store as follows:
router.beforeEach((to, from, next) => {
console.log(store.state.userStore.authUser)// this will log put authUser from userStore module
if (to.matched.some(record => record.meta.requiresAuth) &&
(!store.state.userStore.authUser ||
store.state.userStore.authUser === 'null')){
const authUser = localStorage.getItem('authUser')
console.log('here log');
next({ path: '/', })
}else{
console.log('bhar else redirect');
next()
}
});
The authUser property belongs to the userStore module, so to access it you use
store.state.userStore.authUser