How can I break my Vuex actions into multiple files and still use `dispatch`? - vue.js

I have broken my actions into multiple files to make my project more maintainable and extensible. Trying to dispatch from one action to another, however, is not working.
My file tree looks like this:
store.js
actions
|--actions.js
|--createShape.js
|--addShape.js
My store.js looks like:
import actions from './actions/actions'
const PlaypadStore = {
namespaced: true,
state: {
localState: ''
},
actions: {
...actions,
},
}
My actions.js folder has the following:
import CREATE_SHAPE from './createShape';
import ADD_SHAPE from './addShape';
export default {
CREATE_SHAPE,
ADD_SHAPE,
}
The problem is trying to dispatch ADD_SHAPE from CREATE_SHAPE. My createShape.js looks like the following:
const CREATE_SHAPE = ({ state, dispatch }) => {
return dispatch('ADD_SHAPE')
}
export default CREATE_SHAPE;
But it returns me this:
[vuex] unknown local action type
The question is this: how can I break my actions into multiple files, but still be able to dispatch actions from one to another?

if you use 'export default...' in your action-files and import your files in the store like that:
import actions_one from './actions_one';
import actions_two from './actions_two';
you can then use the spread operator to make it like you're importing one object:
export default new Vuex.Store({
namespaced: true,
actions: {
...actions_one,
...actions_two
},
...

you need to let Vuex know that actions.js, createShape.jsand addShape.jsare "modules" of your store for this to work.
You can read more about it in the Vuex Modules documentation.
Basically you need an index.js file declaring the modules at the root of your store. That should look like this:
import actions from "./actions";
import createShape from "./createShape";
import addShape from "./addShape";
Vue.use(Vuex);
export default new Vuex.Store({
modules: {
actions,
createShape,
addShape
}
});
At this point your dispatch call should work, UNLESS it comes from another vuex store module, in that case just specify "root = true" as they pointed out here.

Related

Using Vuex State in main js

I am trying to use my store state in main.js but it vanishes my component, can I use state in mian.js
Axios.defaults.headers.common['BranchId'] = this.$store.state.myBrachId,
if not what how can I set the default headers dynamically then..?
You're asking how to access a Vuex store outside a Vue component. The syntax that you're currently using is only valid if you're writing a Vue component.
In case you want to access Vuex outside (any .js file) you should, first, export the store. Then, import that store in your file and finally use the store as you place.
Let's see an example:
store/index.js
export const store = new Vuex.Store({
state () {
myBrachId: 'niceBranch007'
}
});
Then, in any other .js file (main.js in your case)
import { store } from 'store/index.js'
console.log(store.state.myBrachId)
If you're trying to add headers to axios I'd ask you to consider if you should really be getting that header data from a Vuex store anyways. Remember that any browser refresh will clear your store so you should not rely on it's availability more than you need to. Using localStorage or sessionStorage might be better for what you're looking to do here.
I am doing this right now this is my store
import Vue from "vue";
import Vuex from "vuex";
Vue.use(Vuex);
export const store = new Vuex.Store({
state: {
branchId: "",
},
getters:{
},
mutations: {
},
actions: {},
modules: {}
});
In header cmponent
this.$store.state.branchId = this.Branches[index].branchId;
in main js
import Axios from 'axios'
import { store } from './store/index'
Axios.defaults.headers.common['BranchId'] = store.state.branchId;
this is not setting axios header, it comes empty

Cannot find declaration to go to Vuex WebStorm?

I added auto import Vuex modules and after that I can't go to Vuex actions/getters/etc from component or another place where I declared.
Now my architecture like this:
index.ts
store
module1.store.ts
module2.store.ts
module3.store.ts
index.ts
store/index.ts:
const requireModule = require.context('.', false, /\.ts$/)
const modules: any = {}
requireModule.keys().forEach(fileName => {
if (fileName === './index.ts') return
const moduleName = fileName
.replace(/(\.\/|\.store\.ts)/g, '')
.replace(/^\w/, c => c.toLowerCase())
modules[moduleName] = requireModule(fileName).default || requireModule(fileName)
})
export default modules
index.ts (sibling store):
export default new Vuex.Store({
modules,
strict: debug,
plugins: debug ? [createLogger()] : []
})
If I use anybody action in component It's work but If I want to go this action from component I can't:
Every store module has:
export default {
namespaced: true,
state,
actions,
getters,
mutations
}
Vuex completion in WebStorm is based on the static code analysis. Unfortunately the syntax used by you is too complex to be statically analyzed, as the module name is dynamically produced from the file name.
Please see comments in WEB-45228 for possible workarounds

Vue.js Vuex cannot access store in router

I've seen that this question have been asked a couple of time but I cannot find any good answer and don't understand why my code is behaving like this.
As said in the title I'm trying to import my store in the router to be able to use my getters on conditional and grant a user to access or not a route.
But as soon as i'm trying to import the store I get the following error:
[vuex] unknown action type: autoSignIn
this is coming from:
const vm = new Vue({
router,
store,
provide,
i18n,
render: handle => handle(App),
created () {
firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.$store.dispatch('autoSignIn', user)
this.$store.dispatch('loadMatter')
this.$store.dispatch('loadFootprints')
this.$store.dispatch('loadMembers')
}
})
So I guess that when my app is starting the store hasn't loaded yet.
How can I workaround that I want to be able to use
store.getters.mygetter
Thank you very much
I think you need to import your store in your router file
I'm doing it like this:
import store from "#/store/index.js";
Are you using modules of vuex?
Can you share your store index file?
https://vuex.vuejs.org/guide/modules.html
If you are using modules of vuex, you should do this.$store.dispatch('module_name/action_name')
I have my store split into files
Vue.use(Vuex);
const store = new Vuex.Store({
state,
actions,
mutations,
getters,
plugins: [
process.env.NODE_ENV === 'development' && createLogger({ collapsed: false }),
].filter(Boolean),
});
export default store;

How to set up vuexfireMutations in Vuex store.js file

I am attempting to build a Vue.js application that utilizes Vuexfire in the store.js file. My store.js file looks something like this:
import Vue from 'vue'
import Vuex from 'vuex'
import { vuexfireMutations, firestoreAction } from 'vuexfire'
import { db } from '#/main'
Vue.use(Vuex)
export default new Vuex.Store({
state: {
items: []
},
mutations: vuexfireMutations,
actions: {
setEvents: firestoreAction(context => {
return context.bindFirestoreRef('items', db.collection('dbItems'))
}),
},
})
I understand from the documentation that the .bindFirestoreRef() method is what binds Firestore to the Vuex store, while firestoreAction is a wrapper that injects .bindFirestoreRef() into the context object, so that it can be used as a method of the store (along the same lines as the commit method). The payload is then committed to mutations, while vuexfireMutations apparently handles the mutation of the state behind the scenes. Does this mean that vuexfireMutations is a method? What is the right term to describe vuexfireMutations? I really don't feel like the documentation explains very well what this imported item is. I'm just kind of having to guess that it is something that handles mutations, but what is the right term for it?

Vuex module not accessible from rootState

I needed to get route's query parameters inside Vuex in order to preload filter settings and update the state of the application. To make this possible I installed vuex-router-sync.
Next step was to synchronize the Vuex and VueRouter.
Router:
Vue.use(VueRouter);
export default new VueRouter({ mode: 'history' });
Store:
Vue.use(Vuex);
export default new Vuex.Store({
modules: { filters: FiltersModule },
plugins: [ FiltersPlugin ]
});
App's bootstrap:
const unsync = sync(store, router);
new Vue({
el: '#restaurant-admin-app',
components: {
'App': AppComponent,
'filters': FilterComponent,
'orders-table': OrdersTableComponent
},
store,
router
});
My FilterPlugin that should trigger the URL parsing:
export default store => {
store.dispatch('filters/parseURLFilterSettings');
}
And now, the funny part, here's the URL parsing action:
parseURLFilterSettings: ({ state, commit, rootState }) {
console.log('RootState:', rootState);
console.log('Route module (incorrect):', rootState.route);
console.log('Filters module (correct):', rootState.filters);
console.log('Object\'s keys:', Object.keys(rootState));
}
What am I doing wrong? I thought it might be something with syncing, but at the end the console.log shows clearly that the route Object is there (and it's not empty), but somehow when I access it, it's undefined. Thank you in advance.
The problem was very well explained here. What it basically says is that the object's value is evaluated when you open it's body in the console.
The problem was I didn't have the route module loaded yet, because I was trying to dispatch an action from a vuex plugin which seems to load before the vuex-router-sync's syncing was done.
The problem was solved when I moved application's bootstrap logic from vuex plugins into the AppRootComponent's mount lifecycle event.
You should import the router-sync. After that your store and routes wil behave properly. I usually do this in the main.js file.
import router from './router'
import store from './store'
import { sync } from 'vuex-router-sync'
sync(store, router)