Nuxt acces vuex store inside mixin - vuex

I m making small mixin for driving animations based on how user is crawling through page and I need to have access to data stored in Vuex store from that mixin.
Any ides how to pass data from vuex store there, I am getting mad.
pages/index.vue
import Vue from 'vue'
import {ToplevelAnimations} from '~/mixins/toplevel_animations'
export default Vue.extend({
mixins: [
ToplevelAnimations
]
})
mixins/toplevel_animations.js
export const ToplevelAnimations = {
transition(to, from) {
// some logic, here I need to access routes stored in store
return (to_index < from_index ? 'switch-to-left' : 'switch-to-right');
}
}
store/index.js
import {StoreExtensions} from "~/plugins/store_extensions.js";
export const state = () => ({
MAIN_NAV_LINKS: [
{
path: '/',
title: 'Domov',
order: 1
},
// ...etc
],
CURRENT_PAGE_INDEX: 1
})
export const getters = {
getMainNavLinks: (state, getters) => {
return state.MAIN_NAV_LINKS
}
// ..etc
}
export const mutations = {
setCurrentPageIndex(index) {
state.CURRENT_PAGE_INDEX = index
}
// ...etc
}
export const actions = {
nuxtServerInit ({ commit }, req ) {
var page_index = StoreExtensions.calculatePageIndex(req.route.path, state.MAIN_NAV_LINKS)
mutations.setCurrentPageIndex(page_index)
}
}

I never used Vue.extend(), always using .vue files, so it might be different (although it should not). From my experience with mixins in both Vue and Nuxt seems that mixins receive the relevant this context when they are assigned to components. So for me using simple this.$store worked.

Related

Can a Vue component/plugin have its own pinia state, so that multiple component instances don't share the same state

I have a "standalone" component which is set up as a Vue plugin (to be downloaded via npm and used in projects) and it uses pinia, but it looks like multiple instances of the component share the same pinia state. Is there a way to set up pinia such that each component instance has its own state?
The component is made up of multiple sub-(sub)-components and I'm using pinia to manage its overall state. Imagine something fairly complex like a <fancy-calendar /> component but you could have multiple calendars on a page.
I have the standard pinia set up in an index.js:
import myPlugin from "./myPlugin.vue";
import { createPinia } from "pinia";
const pinia = createPinia();
export function myFancyPlugin(app, options) {
app.use(pinia);
app.component("myPlugin", myPlugin);
}
Then myPlugin.vue has:
<script setup>
import { useMyStore } from '#/myPlugin/stores/myStore'
import { SubComponent1 } from '#/myPlugin/components/SubComponent1'
import { SubComponent2 } from '#/myPlugin/components/SubComponent2'
...
const store = useMyStore()
The sub-components also import the store. Also some of the sub-components also have their own sub-components which also use the store.
myStore.js is set up like this:
import { defineStore } from "pinia";
export const useMyStore = defineStore("myStore", {
state: () => ({
...
}),
getters: {
...
},
actions: {
...
}
});
Edit: This is the solution I ended up using:
myStore.js:
import { defineStore } from "pinia"
export const useMyStore = (id) =>
defineStore(id, {
state: () => ({
...
}),
getters: {},
actions: {},
})();
myPlugin.vue
...
<script setup>
import { provide } from "vue"
import { useMyStore } from '#/MyNewPlugin/stores/MyStore'
import { v4 } from "uuid"
const storeId = v4()
provide('storeId', storeId)
const store = useMyStore(storeId)
...
SubComponent1.vue
<script setup>
import { inject } from "vue"
import { useMyStore } from '#/MyNewPlugin/stores/MyStore'
const storeId = inject('storeId')
const store = useMyStore(storeId)
</script>
A simple way of solving this is to create a stores map, using unique identifiers:
When you init a new instance of the root component of your plugin, you create a unique identifier for the current instance:
import { v4 } from 'uuid'
const storeId = v4();
You pass this id to its descendants via props or provide/inject.
Whenever a descendent component calls the store, it calls it with the storeId:
const store = useMyStore(storeId)
Finally, inside myStore:
const storesMap = {};
export const useMyStore = (id) => {
if (!storesMap[id]) {
storesMap[id] = defineStore(id, {
state: () => ({ ... }),
actions: {},
getters: {}
})
}
return storesMap[id]()
}
Haven't tested it, but I don't see why it wouldn't work.
If you need hands-on help, you'll have to provide a runnable minimal reproducible example on which I could test implementing the above.

Vuex store is inaccessible

I made a vuex store:
export const general = {
namespaced: true,
state: {
menuEnabled: true,
headerEnabled: true
},
getters: {
menuState: state => state.menuEnabled,
headerState: state => state.headerEnabled
},
actions: {
setMenuVisibility({commit}, visibility) {
commit('setMenuVisibility', visibility);
},
setHeaderVisibility({commit}, visibility) {
commit('setHeaderVisibility', visibility);
}
},
mutations: {
setMenuVisibility(state, visibility){
state.menuEnabled = visibility;
},
setHeaderVisibility(state, visibility){
state.headerEnabled = visibility;
}
}
}
index.js
import { createStore } from "vuex";
import { auth } from "./auth.module";
import {general} from "./general.module";
const store = createStore({
modules: {
general,
auth
},
});
export default store;
main.js
import router from "./router";
import store from "./store";
createApp(App)
.use(store)
.use(router)
.mount('#app')
After that, I created 2 computed functions in App.vue:
computed: {
menuVisibilityState : function (){
return this.$store.state.menuEnabled;
},
headersVisibilityState : function () {
return this.$store.state.headerEnabled;
}
}
But, I can't get them from vuex:
I tried to import general directly in App.vue and get the values.
It doesn't work and I think, that it's bad way to get them.
Can somebody help me?
When you create a module in Vuex, the local state is nested depending on the name you've provided to the module (this happens when you're accessing the root state.).
In your example, to access the local state of general module you could write:
computed: {
menuVisibilityState : function (){
return this.$store.state.general.menuEnabled;
},
headersVisibilityState : function () {
return this.$store.state.general.headerEnabled;
}
}
Keep in mind that:
actions and mutations are still registered under the global namespace - this allows multiple modules to react to the same action/mutation type. Getters are also registered in the global namespace by default.
https://vuex.vuejs.org/guide/modules.html#namespacing

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 to access router from nuxtjs store?

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

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
}