How to access router from nuxtjs store? - vuex

I tried this but only got an error message
This relative module was not found:
* ./router in ./store/index.js
// Ran with yarn dev
import router from './router'
export const state = () => ({
authenticated: false,
})
export const mutations = {
toggleLogin(state, loginStatus, path) {
state.authenticated = loginStatus
if (loginStatus) {
router.push(path)
} else {
router.push('login')
}
},
}
My store path is store/index.js

Vuex mutations and getters doesn't have access to the Vue context. Only actions does.
Also, you can't import the Nuxt router like that. What's that file you're trying to import?
I'd suggest to make an action instead:
export const actions: {
toggleLogin({ commit }, payload) {
this.app.router.push('') //exists
}
}

Related

Modules vs Multiple vuex store files

I am working on a project using vue and vuex. And I think most of the people are having the problem, after sometime the store.js (or index.js) is getting too big. So I want to split the store.js file. After some google I found I can use Modules to overcome this problem. BUT I tried also with creating a new Instance of vuex and it works perfectly fine.
Single instance with modules :
---store.js
import Vuex from "vuex";
import thisismodule1 from "./modules/module1";
import thisismodule2 from "./modules/module2";
const createStore = () => {
return new Vuex.Store({
modules: {
module1: thisismodule1,
module2: thisismodule2
}
});
};
export default createStore;
const store = new Vuex.Store({
module
});
Multiple files with multiple instances:
---storeCar.js
---storeHouse.js
---storeTree.js
...
So my question is, is this allowed or do I have to use modules with single instance?
Thank you in advance!
there is a best practice for that:
Create a file. that's name is Shared
Create a Store folder and create a modules folder on it:
you should modules in the modules folder and define your store for a target:
for example:
import * as types from "../types";
const state = {
currentPage: {}
};
const getters = {
[types.avatarManagement.getters.AVATAR_MANAGEMENT_GET]: state => {
return state.currentPage;
}
};
const mutations = {
[types.avatarManagement.mutations.AVATAR_MANAGEMENT_MUTATE]: (
state,
payload
) => {
state.currentPage = payload;
}
};
const actions = {
[types.avatarManagement.actions.AVATAR_MANAGEMENT_ACTION]: (
{ commit },
payload
) => {
commit(types.avatarManagement.mutations.AVATAR_MANAGEMENT_MUTATE, payload);
}
};
export default {
state,
getters,
mutations,
actions
};
Create index.js for define Vuex and import your modules:
index.js file:
import Vue from "vue";
import Vuex from "vuex";
import avatarManagement from "./modules/avatarManagement";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
avatarManagement
}
});
5) also you can types of your vuex store on Type.js file:
type.js:
export const avatarManagement = {
getters: {
AVATAR_MANAGEMENT_GET: "AVATAR_MANAGEMENT_GET"
},
mutations: {
AVATAR_MANAGEMENT_MUTATE: "AVATAR_MANAGEMENT_MUTATE"
},
actions: {
AVATAR_MANAGEMENT_ACTION: "AVATAR_MANAGEMENT_ACTION"
}
};
***for get data from Store:
computed: {
...mapGetters({
registrationData:types.avatarManagement.AVATAR_MANAGEMENT_GET,
getDataFromStore() {
return this.registrationData;
}
}
***for Change data to Store and mutate that:
methods: {
goToActivity() {
const activity = {
companyList: this.categories
};
this.$store.commit(types.avatarManagement.AVATAR_MANAGEMENT_MUTATE, {
newData
});
},
}

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 duplicate namespace auth/ for the namespaced module auth

I am using nuxt.js with the auth module.
Every time i open a new page on my profile this error message appears.
I have created a mixin called auth.js in my plugins/mixins directory. This file contains the code:
export const getters = {
authenticated(state) {
return state.loggedIn;
},
user(state){
return state.user;
}
};
I've created a getter file called auth.js with the following code:
import Vue from 'vue'
import {mapGetters} from 'vuex'
const User = {
install(Vue, options) {
Vue.mixin({
computed: {
...mapGetters({
user: 'auth/user',
authenticated: 'auth/authenticated'
})
}
})
}
};
Vue.use(User);
The getters and mixin work, but everytime i open a page it gives me this error and i dont know how to solve it. I've tried the solutions in this question:
duplicate namespace auth/ for the namespaced module auth
Altough this does solve the errors, it makes my getters undefined.
Yeah, I found a workable way ...
Switch to index.js auth.js logic, and delete auth.js.
index.js
export const getters = {
authenticated(state) {
return state.auth.loggedIn
},
user(state) {
return state.auth.user
}
}
Revise it as follows if you are using a user.js mixin:
import Vue from 'vue'
import {mapGetters} from 'vuex'
const User = {
install(Vue, options) {
Vue.mixin({
computed: {
...mapGetters({
user: 'user',
authenticated: 'authenticated'
})
}
})
}
};
Vue.use(User);
Plugins:
** Plugins to load before mounting the App
*/
plugins: ["./plugins/mixins/user.js"
],

Vuex-persistedstate does not work after refreshing a page

I am making a spa app with laravel and vue, and I would like to keep my login information in vuex's state after refreshing a page.
I typed
sudo npm install vuex-persistedstate
and installed Vuex-persistedstate and set the plugins as below.
import Vue from 'vue' import Vuex from 'vuex'
import auth from './auth'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)
const store = new Vuex.Store({
modules: {
auth,
plugins: [createPersistedState()],
}
})
export default store
I expected my data to be kept after refreshing a page but it was not.
I checked what is going on, and it seems the plugin object was empty.
it seems that I cannot import the plugins for some reason, but I do not know why.
Could someone help me, please?
my module file
const state = {
user: null,
salonId: null
}
const getters = {
check: state => !! state.user,
checkSalonId: state => {return state.salonId},
}
const mutations = {
setUser (state, user) {
state.user = user
},
setSalonId (state, salonId) {
state.salonId = salonId
}
}
const actions = {
async currentUser (context) {
const response = await axios.get('/api/user')
const user = response.data || null
context.commit('setUser', user)
},
async logout (context) {
context.commit('setUser', null)
context.commit('setSalonId', null)
},
async currentSalon (context, salonId) {
context.commit('setSalonId', salonId)
}
}
export default {
namespaced: true,
state,
getters,
mutations,
actions,
}
You placed plugins in the wrong place. plugins should be inline with modules, not inside modules.
Please take a look at this differences.
const store = new Vuex.Store({
modules: {
auth,
plugins: [createPersistedState()]
}
})
VS
const store = new Vuex.Store({
modules: {
auth
},
plugins: [createPersistedState()]
})
I think you need to setup an option object with the modules you wanna persist. In this example i'm persisting the user module from my store (haven't include the import code)
const persistedStateOptions = {
paths: [
'user',
]
}
export default new Vuex.Store({
modules: {
user,
},
plugins: [createPersistedState(persistedStateOptions)]
})
Look at difference in paths.This worked for me.
import createPersistedState from 'vuex-persistedstate';
Vue.use(Vuex);
export default new Vuex.Store({
strict:true,
modules:{
party,
contract
},
plugins: [createPersistedState(
{
paths:['party.selectedParty']
}
)],
});
Where party is the module name and selectedParty is the name of module state.
Now this plugin only taking care of selectedParty state.
The vue components that get data via state from DB should be kept out of this plugin.

Access the state of store or getters? _WEBPACK_IMPORTED_MODULE_3__store___.a.dispatch is not a function

I am trying to verify if the user is authenticated to be able to give access to the route that is directed otherwise redirect to the login route, the problem is that I do not know how to execute the fetchUser action from my beforeEach. In other words, I can't access my getter from the router script.
store.js
import mutations from './mutations';
import actions from './actions';
import getters from './getters';
export default {
state: {
isLoggedIn: !!localStorage.getItem("token"),
user_data : localStorage.getItem("user_data"),
},
getters ,
mutations,
actions
}
routes/index.js
import Vue from 'vue'
import VueRouter from 'vue-router'
Vue.use(VueRouter)
import routes from './rutas';
import store from '../store/';
const router = new VueRouter({
mode : 'history',
routes
})
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
if (!store.getters.isLoggedIn) {
next({path: '/login'})
}
else {
store.dispatch('fetchUser') // Line error
next()
}
}
else {
next() // make sure to always call next()!
}
})
getters.js
export default {
isLoggedIn: state => {
return state.isLoggedIn
},
user_name : state =>{
if(! _.isEmpty(this.user_data))
return JSON.parse(state.user_data).name
return '';
},
isEmptyUser : state =>{
return _.isEmpty(this.user_data);
},
isAdmin: state => {
if(! _.isEmpty(this.user_data)) return state.user_data.nivel===1
return false;
}
}
actions.js
export default {
/* more methods*/
, async fetchUser({ commit }) {
return await axios.post('/api/auth/me')
.then(res => {
setTimeout(() => {
localStorage.setItem("user_data", JSON.stringify(res.data));
Promise.resolve(res.data);
}, 1000);
},
error => {
Promise.reject(error);
});
}
This returns error in console:
_WEBPACK_IMPORTED_MODULE_3__store___.a.dispatch is not a function
How can I do or the approach is the wrong one and I should not access actions directly?
The problem is your store is not the actual store object, it is just the object used to generate it.
A solution is to have the file export the real store:
import Vue from 'vue';
import Vuex from 'vuex';
import mutations from './mutations';
import actions from './actions';
import getters from './getters';
Vue.use(Vuex); // added here
export default new Vuex.Store({ // changed here
state: {
isLoggedIn: !!localStorage.getItem("token"),
user_data : localStorage.getItem("user_data"),
},
getters ,
mutations,
actions
}) // changed here
Now your router code would work.
What you must be aware as well is that somewhere, probably in your main.js, you had the store being initialized like above. For example:
import store from '../store/';
new Vue({
store: new Vuex.Store(store),
// ...
})
Now you must remove that initialization and use the store directly:
import store from '../store/';
new Vue({
store: store, // or simply store
// ...
})
And all should be good.